From 355d64b9412c14555781226d1a857a053604e1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henri=20Hyyryl=C3=A4inen?= Date: Fri, 13 Apr 2018 19:59:29 +0300 Subject: [PATCH] Engine refactor (#540) * Organelle now sets the collision sphere offset and successfully parents its scenenode to the microbe * Fixed remaining forgetting to unparent Ogre::SceneNodes first * Added LoadGameButton code to thrive_menus.txt * Added a update method to thrive_menus.txt.Also yeah i cant seem to call any of the "useful" functions lke FileSystem::FileExists , i can however call the "get" methods for the things i wamt, how odd. * Added ExtraAccess for menu scripts and uncommented load game button setting * Accidentally committed by intro skipping code, whoops * Spawning a microbe now doesn't assert * removed now useless main menu folder * Removed extra debug print * working on load code, added old sound function (commented out to thrive_menus.txt) * Restoring the membrane color yay * Apparently i didn't commit it for some reason * Added loadSaveGame method, made the script call it when loading, of course it will just start a new game right now, (as i need to actually write the save code and the load code for the player microbe separately, but i think i have a pretty good idea as to how to progress, still learning the new engine. * Un-inverting the hex coordinates * fixing a bit of the movement organelles * Fixed the c++ definition of loadSaveGame not matching the angelscript registering String was by value and angelscript called it by reference * Added 2D constraints to stop the cell from falling, some random debugging code * Removed useless file * Changed the second debug cell spawn location * Fixed giving the cells their initial compounds * The player cell can now move forwards out of the camera view * Spinning around automatically works great now * Somewhat working movement and rotation * Made rotation be set directly and attempted to change the physics creation to stop the NaNs but didn't work * Fixing the camera * Added microbe stage intro video, and it is skippable. * Tweaked the microbe intro player to properly set the GUI afterwards and other slight tweaks to it * Changed the background to be slightly larger (this seems to stretch the background texture) * Made the autostart work again and cleaned up some comment in empty block * Movement direction is now maybe a bit better but this also needs a math wizard * Maybe fixed the movement finally * Another test that seems to work the best so far * The movement is now properly fixed But the orientation still uses the direct setting method * Updated setup and added fast(er) script for recompiling just the engine and thrive * I enabled the debug spawning of an additional cell for physics testing * Added a clang format file, which we'll start using at some point * Fixed uninitialized Ogre::Matrix4 use and the cells now collide * Changed the cell physics body creation to be slightly more efficient * Commented out the unused movement code * microbe hud now gets the player's atp but does nothing with it * ATP count is now shown on the compound bars * Removed old cmake things. And updated all of the documentation * Added a new file "setup.as" for the microbe stage tutorial and started working on converting from the lua code * Added info about forking and fixed one invalid code example * Cleaned up some old test code in ThriveGame and made the background back to a fully static plane It now definitely looks better than before * found spawn code, removed comments around function brackets and tabbed in commented out code so its easy to see. * Fixed syntax errors in setup.as and made the setup be called from a single function * Made QuickRecompile pull Leviathan updates * Made the compound panel less blurry * The ATP bar now works * trying to figure out how to spawn things. * Planning in setup.as not sure how register_microbe_components got there, it cna probabbly be delete dthough. * modularized code a bit more * script component registering is in setup.as * Enabling the spawning code in species_system which should have the species spawning instead of setup.as Also fixed using signed index for looping * Put in a basic ai (most of it is commented out). Things almost can spawn * Removed a typo * Tweaks to make the membrane change colour whenever called, and other small c++ side tweaks * The spawn system now creates visible cells but prints tons of errors * Added a Release method to spawn system, which doesn't seem to be really needed * Fixed return type from script spawn system function * Commented out debug spam * The spawned cells now move randomly * Removed more TODO: outputs * Added missing atomic include * Biome angelscript code now gets called * All micobes were defaulting to white, now they get random colours. * The change background material now works * Refactored the debug code a bit in biome.as * Made a hack to fix the cells blinking for a frame at origin. This is caused becase the rendernodeposition is applied before spawn system is ran * Added files for Microbe_editor * Fixed spawn system spawning things at a slight offset from 7 = 0 * Put the really smooth turning back in * Got all compound bars working (#547) * Created tutorial folder inside microbe_stage * Deleted setup and manifest files * Got all other compound bars working * Fixed glucose bar * fixed oxygen bar * Compound cloud system definetly not running * Was trying to get compound clouds to spawn, i failed * removed wrongly implemented compoundcloudsystem code commented where system should be inserted in ruby (though i don't know how to insert it) also added opaqueness randomization for species, and when they split they only change color rarely (this should be actual new clade stuff i think) * Enabled running the compound cloud system * Removed unneeded includes * Deleted old registries that should not be used * The compound cloud planes now spawn. They are invisible and rotated wrong * Trying to get the clouds to show up. The plane orientation is now right but for some reason the texture update fails And it seems that only one of the passes is rendered. Ogre 2.1 might have something to do with that * The oxygen clouds now show up but the repositioning the plane is broken So they jump all over the place * The flagella animation is now applied (but the orientation and material is a bit broken) * Desaturated cells a bit, found a good balance (suggested by nicktehnick) * we now take saturation and multiply it by .75 to mute the colors a bit * The health bar also works now, removed the commented out lua versions of the bars * Free floating organelles now spawn properly and have collisions and stuff all set up. The only issue is that they appear to all be spawning at 0,0,0 despite pos being random. Im sure its a simple to fix issue. * Changed the spawn to use a raw function * fixed positioning of free spawned organelles * gave free floating organelles some physics. * Started redoing the clouds, now they spawn but don't receive any compounds yet. Also I enabled clang format for my editor So expect a lot of changes until everything is formatted that way. Oh and the clouds are probably super broken, but this runs * Trying to figure out why all organelles aren't removed from a microbe * Fixed PlacedOrganelles not being handled when microbe was destroyed * Drawing a debug cloud now works * Some sort of line is spawned but not much else * changed z to y, it appears to have reduced teh cloud size and mad eit less ridicoulous, its still spawning at width, 0 instead of 0,0 though. * it spawns at 0,0 now. * Since the line is no longer needed since its spawning at the right location, removed the weird line * added a comment * fixed m_position in a more permanent way woo, now we can move on to more interetsing things :P * _needsColourUpdate now gets called * Added comments about the coordinate system used in the cloud * Clouds now work somewhat (committing just in case I break it later) * Commented out the spam of "Update colour" * Fixed the timestepping so now it looks a bit better * Trying to get the absorber working again * Some sort of absorption happens around the clouds spawning at origin * Disabled debugging printing * Added code to set the tint of an organelle (currently disabled so it should look the same) * Enabled the tinting and fixed a few other places that used the organelle models without the parameter * Registered vector4 with angelscript alongside constructor, need to register Item::setCustomParameter(const int, Vector4) though now. * removed vector4 stuff that was added earlier (the negien should handle that) added a changeModelTint method * Organelles now get tinted properly * Can now mess with hue saturation and brightness of organelles just like the membrane * Revert "removed vector4 stuff that was added earlier (the negien should handle that) added a changeModelTint method" This reverts commit a48f5bfa10ef583c84caf2a34cd80a7be8081207. * Revert "Organelles now get tinted properly" This reverts commit 6f1fb5a42eef9f9a8a77572fce9e4807eda87b0d. * Revert "Can now mess with hue saturation and brightness of organelles just like the membrane" This reverts commit 04909dbedbb19f86a3f20aac34376ea06e0ce167. * Revert "Registered vector4 with angelscript alongside constructor, need to register Item::setCustomParameter(const int, Vector4) though now." This reverts commit c9ce57eb95d4bd0ff928a1c91f7a78645018d30f. * Updated the one place where sound playing is used * Menu music now plays and never stops * Added copying the engine pdb for better windows debugging, also apparently I forgot to push my script changes... * Updated setup system * Implemented calculateHSLForOrganelle for organelle hue shifting * used proper values and changed method to return a float4 rather then a colour value. * if you comment out setHsb it doesnt crash. * applied hue shifting to the flash color aswell. * i forgot to commit this (it multiplies saturation by two now derp ) * add button click sound effects to main menu * fixed typo hhereylonem noticed * was trying to seperate the playing music code from the playing video code, but since if i do it any other way it plays during the intro video i just gave up and am going to work on microbe sound now, also deleted music player object. * Got ambient sounds working in the microbe stage, also comemnted out main menu music becaus eit annoyed me and mad eit harder to test the microbe stage ambient sounds :P * removed ambient code from setup.as since its working in the angel script now. * The split sound now plays * re-Implemented death sound and toxin sound. * Began implementing differnet sunlights for each biome * COntinue dimplementing biome colours, they now have rgb values and get turned into colourvalues * fixed sound bug, biome.as now calls set sunlight with the new properties. it doesnt appear to be actually changing the colours though, im sure its a simple fix. * hmm, its grabbing all the right values an dlogging them, but set sunlight just isnt working. * Fixed events for new leviathan version * The main menu music now starts after the intro and keeps playing until the menu is hidden and the microbe gui is shown * Fixed the CEGUI event returning wrong type * Moved the Moved the ambienceSounds object to the hud system As it is only used from there and it's a bit questionable as a global variable * Fixed typo * Made the ambient tracks a global constant and added a TODO comment about duplicated code * Refactored the ambient playing code + fixed one bug where microbe audio 2 might have been attempted to be played It doesn't exist * Reformatted ThriveGame with clang format * implemented the proper lighting orientation for biome lighting colours. * some minor biome changes * fixing off-by-one bug * Added physics callback for detecting cells hitting floating organelles * fixed orientation for er golgi and "sometimes" mitochondria. Eg the mitochondria on the main cell is fixed, but not all of the mitochondria are fixed. * Fixing crash when closing in the main menu * fixed orientation for everything except the nucleous. * Fixed all rotations, er and golgi are also fixed, also fixed the nucelous, everything appears to be fixed. * Updated setup to point to new leviathan URL * Fixed building with new Leviathan path name * Made key rebinding by editing ThriveKeybindings.conf possible * Golgi is now rotated correctly, added tints to golgi and er aswell. * Made ambient sound loop that is meant to be played along side the ambient music play properly, its a bit loud though. Player cell is now white instead of the ugly saturated dark purple that didnt fit with the other cells. * Added basic proof of concept prokayotes to the game, and they spawn alongside normal microbes aswell, and are subject to auto-evo. * Revert "Added basic proof of concept prokayotes to the game, and they spawn alongside normal microbes aswell, and are subject to auto-evo." This reverts commit 9cb4ff948012b1e691888b323c76fc6f50726f12. * fixed bug where oxytoxy bacteria never spawned. * Bacteria no longer get AI (bacteria and normal microbe ai should likely be seperate), also species component now has a variable that lets us know if its a prokayote. * Almost fixing the spawn system * Completed the spawn system fix yay * re-implemented sound volume change * re-implemented sound volume change * Disabled the master server check (as it is a long way off) * added 3 new organelles for prokayotes: Respiratory Protein Photosyntehsizing Protein Oxytoxy synthesis protein Bacteria use these organelles only also scaled bacteria down to proper "bacteria" size. * bacteria now spawn in groups of 1-3, its an expensive method so i think we can improve that efficiency a bit. Next i need to clean up the code and make bacteria a subclass of species instead of the way it currently works, and i need to make sure that normal microbes and bacteria dont have access to the same organelles. * bacteria no longer spawn with y values added (that was a stupid mistake) * fixed typo * removed "no ai" log, it has outlived its purpose for now. * made it only queue up a couple entities at once for deleting to reduce lag spikes a bit. * commented out AABB overlap log * set prokayote organelle chances to 0 so euakayotes can't use them, until i have eukaryotes & prokayotes seperated more. * bacteria can now spawn in either line shaped colonies or clump shaped colonies, also increased size of colonies * The flagella material now somewhat works (seems to only show the scene ambient light or be black) * Setting the sunlight to very extreme power seems to make the flagella not appear black anymore * Updated the light setting with the new parameters * Added the place where gamma correction could be enabled for compound clouds But it makes them look much fainter so currently shouldn't be enabled * Commented out cell physics callback printing * Editor button can now be enabled and it calls a function when it is pressed * Removed the converted lua scripts from microbe_stage * GUI now has the event for moving to the editor GUI state update * Removed even more old files that don't need converting. And moved the editor GUI to the right file * Initial automatic conversion of microbe editor (this is most likely broken). Also world switching * Removed the menu skipping I once again committed * Slight tweaks to get the compiler errors about the editor scripts to start rolling in * Removed a bunch more of old files * Working on getting the editor working. Some basic commented out code and switching attemp is in this commit * Going to the editor and coming back works, it even pauses sound. But the editor does nothing * Fixed some newlines in the editor so now they show up * Updated setup to get new fixes * Now runs with latest engine, but it is revolutionary games website simulator * Now just moves straight to the cell stage (GUI doesn't work yet) * Simplifying membrane code a bit using triangle fans * bacteria now start with a spawned component so colonies can be offloaded. * reduced the amount of times the membrane code calls per step (from 50 to 40), which should make things a little less laggy and didnt effect the membrane look at all. * fixed comment * Updated setup to allow running without arguments passed to leviathan setup * Movement now works normally (as far as I can tell, goes with leviathan commit a73a923b) * Started on the HTML GUI * Added new method for spawning bacterial colonies since they despawned instantly,turns out their spawn radius number needed to be squared, as in the spawn system it also gets squared. This will also allow us to difffernetiate them better. * Added cellWallComponent which is a subclass of the membrane component, the only difference between the two is the drawMembrane function right now * membrane component destructor is now virtual so derived classes will automatically call it. * made cellwallcomponent override base getMovement method * applied gamma correction and compensated for it by adding more color variety * Properly started on the GUI. Also no longer directly goes to the cell stage * Added symlink creation for directly viewing the thrive GUI from the scripts/gui folder * Added one box that looks like something * Switched the background mesh generation code to the one in leviathan * Removed old files. And reformatted 2 files with clang format * Fixed compiling after merge with latest engine * Removed schemes and other older GUI files that aren't needed as reference for converting * Fixed setup creating recursive symlinks on linux * Added some more buttons and basic foundation for the GUI * The new GUI now has a working quit button * Mild refactoring of bacteria colony spawn code * Revert "Mild refactoring of bacteria colony spawn code" This reverts commit 2e60bc81cbb4b87f398705d256b832fa17fab4d1. Also committed correct code * Gamma correction now enabled properly. * played around with things, ambient either doesnt work or i mad eit too bright. :) * reset biome.as ambient colour code to what it was when i took that awesome screenshot --- .clang-format | 75 + .gitignore | 18 +- .gitmodules | 9 +- CMakeLists.txt | 700 +- LICENSE.txt | 2 +- QuickRecompile.rb | 7 + README.md | 60 +- RubySetupSystem | 1 + SetupThrive.rb | 268 +- cmake_modules/FindBoost.cmake | 1212 -- cmake_modules/FindCEGUI.cmake | 180 - cmake_modules/FindFFMPEG.cmake | 164 - cmake_modules/FindFreetype.cmake | 49 - cmake_modules/FindOGRE.cmake | 546 - cmake_modules/FindOIS.cmake | 65 - cmake_modules/FindOgg.cmake | 29 - cmake_modules/FindOgreFFMPEG.cmake | 48 - cmake_modules/FindOpenAL.cmake | 35 - cmake_modules/FindPackageHelper.cmake | 309 - cmake_modules/FindPkgMacros.cmake | 144 - cmake_modules/FindTinyXML.cmake | 56 - cmake_modules/FindVorbis.cmake | 36 - cmake_modules/FindcAudio.cmake | 31 - cmake_modules/FindirrKlang.cmake | 84 - cmake_modules/LibFindMacros.cmake | 112 - cmake_modules/LibraryPathHints.cmake | 47 - cmake_modules/PreprocessorUtils.cmake | 59 - cmake_modules/add_to_project.cmake | 57 - cmake_modules/compiler_flags.cmake | 53 - cmake_modules/findMyGUI.cmake | 146 - cmake_modules/utils.cmake | 56 - contrib/googletest | 1 - contrib/lua/building.txt | 6 - contrib/lua/luajit | 1 - contrib/lua/sol.hpp | 14018 ---------------- contrib/lua/sol_changes.txt | 8 - doc/angelscript_primer.md | 78 + doc/clang_format.md | 17 + doc/engine_overview.dox | 121 - doc/engine_overview.md | 64 + doc/entity_component.dox | 63 - doc/entity_component.md | 50 + doc/lua_primer.dox | 142 - doc/main.dox | 21 - doc/quicktips.md | 31 +- doc/scripting.dox | 26 - doc/setup_instructions.md | 141 + doc/{style_guide.dox => style_guide.md} | 164 +- linux_setup/DepGlobber.rb | 62 - linux_setup/RubyCommon.rb | 53 - linux_setup/RubySetupSystem.rb | 1556 -- linux_setup/RunCodeIndexing.rb | 26 - linux_setup/WinInstall.rb | 17 - linux_setup/readme.md | 101 - mingw_setup/.gitignore | 3 - mingw_setup/7zip/install.ps1 | 51 - mingw_setup/OpenAL/install.ps1 | 120 - mingw_setup/OpenAL/install.sh | 69 - mingw_setup/TinyXML/CMakeLists.txt | 34 - mingw_setup/TinyXML/TODO-ADD-SH | 0 mingw_setup/TinyXML/install.ps1 | 141 - mingw_setup/boost/install.ps1 | 136 - mingw_setup/boost/install.sh | 77 - mingw_setup/bullet/install.ps1 | 123 - mingw_setup/bullet/install.sh | 62 - mingw_setup/cAudio/install.ps1 | 141 - mingw_setup/cegui/install.ps1 | 150 - mingw_setup/cegui/install.sh | 62 - mingw_setup/cegui_dependencies/install.ps1 | 133 - mingw_setup/cegui_dependencies/install.sh | 62 - mingw_setup/cmake/install.ps1 | 87 - mingw_setup/cmake/install.sh | 49 - mingw_setup/configure_toolchain.cmake | 1 - mingw_setup/ffmpeg/install.ps1 | 167 - mingw_setup/gtest/install.ps1 | 58 - mingw_setup/gtest/install.sh | 48 - mingw_setup/lua51.dll | Bin 456783 -> 0 bytes mingw_setup/luajit.exe | Bin 28090 -> 0 bytes mingw_setup/luajit/install.ps1 | 50 - mingw_setup/mingw/install.ps1 | 84 - mingw_setup/mingw/install.sh | 49 - mingw_setup/ogg/CMakeLists.txt | 34 - mingw_setup/ogg/install.ps1 | 117 - mingw_setup/ogg/install.sh | 62 - mingw_setup/ogre/install.ps1 | 131 - mingw_setup/ogre/install.sh | 74 - mingw_setup/ogre_dependencies/install.ps1 | 117 - mingw_setup/ogre_dependencies/install.sh | 89 - mingw_setup/readme.txt | 273 - mingw_setup/setup-logged.ps1 | 1 - mingw_setup/setup-logged.sh | 1 - mingw_setup/setup.ps1 | 58 - mingw_setup/setup.sh | 71 - mingw_setup/toolchain_linux.cmake.in | 51 - mingw_setup/toolchain_win.cmake.in | 72 - mingw_setup/utils.ps1 | 28 - mingw_setup/utils.sh | 121 - mingw_setup/vorbis/CMakeLists.txt | 111 - mingw_setup/vorbis/install.ps1 | 120 - mingw_setup/vorbis/install.sh | 62 - ogre_cfg/plugins.cfg | 18 - ogre_cfg/plugins_d.cfg | 18 - ogre_cfg/resources.cfg | 29 - .../MicrobeStage/Bacteria.json | 44 + .../MicrobeStage/BioProcesses.json | 71 + .../MicrobeStage/Biomes.json | 156 + .../MicrobeStage/Compounds.json | 97 + .../MicrobeStage/Organelles.json | 226 + .../MicrobeStage/Species.json | 19 + .../MicrobeStage/SpeciesNames.json | 51 + .../MicrobeStage/StartingCompounds.json | 5 + scripts/class.lua | 101 - scripts/constants.lua | 11 - scripts/game.lua | 85 - scripts/gui/MainMenu.layout | 1934 +++ scripts/gui/gui_common.js | 15 + scripts/gui/main_menu.js | 15 + scripts/gui/microbe_gui_events.as | 305 + scripts/gui/thrive_gui.html | 38 + scripts/gui/thrive_menus.txt | 462 + scripts/gui/thrive_style.css | 144 + scripts/lua_engine/game_state.lua | 247 - scripts/lua_engine/keymap.lua | 85 - scripts/lua_engine/lua_engine.lua | 460 - scripts/lua_engine/manifest.txt | 9 - scripts/lua_engine/system.lua | 63 - scripts/lua_notes.md | 178 - scripts/main_menu/main_menu_hud.lua | 122 - scripts/main_menu/manifest.txt | 4 - scripts/main_menu/setup.lua | 71 - scripts/manifest.txt | 21 - scripts/microbe_editor/manifest.txt | 7 - scripts/microbe_editor/microbe_editor.as | 592 + scripts/microbe_editor/microbe_editor.levgm | 22 + scripts/microbe_editor/microbe_editor.lua | 547 - scripts/microbe_editor/microbe_editor_hud.as | 530 + scripts/microbe_editor/microbe_editor_hud.lua | 520 - scripts/microbe_editor/setup.as | 106 + scripts/microbe_editor/setup.lua | 115 - scripts/microbe_stage/agent_vacuole.as | 70 + scripts/microbe_stage/agent_vacuole.lua | 62 - scripts/microbe_stage/agents.as | 43 + scripts/microbe_stage/bacteria_system.lua | 270 - scripts/microbe_stage/bacteria_table.lua | 33 - scripts/microbe_stage/biome.as | 117 + scripts/microbe_stage/biome.lua | 59 - scripts/microbe_stage/biome_table.lua | 79 - scripts/microbe_stage/compound_table.lua | 88 - scripts/microbe_stage/configs.as | 211 + scripts/microbe_stage/configs.lua | 107 - scripts/microbe_stage/hex.as | 89 + scripts/microbe_stage/hex.lua | 210 - scripts/microbe_stage/manifest.txt | 31 - scripts/microbe_stage/microbe.as | 933 + scripts/microbe_stage/microbe.lua | 1328 -- scripts/microbe_stage/microbe_ai.as | 380 + scripts/microbe_stage/microbe_ai.lua | 352 - scripts/microbe_stage/microbe_control.lua | 56 - scripts/microbe_stage/microbe_operations.as | 1079 ++ scripts/microbe_stage/microbe_stage.levgm | 34 + scripts/microbe_stage/microbe_stage_hud.as | 930 + scripts/microbe_stage/microbe_stage_hud.lua | 770 - scripts/microbe_stage/movement_organelle.as | 264 + scripts/microbe_stage/movement_organelle.lua | 168 - scripts/microbe_stage/nucleus_organelle.as | 106 + scripts/microbe_stage/nucleus_organelle.lua | 94 - scripts/microbe_stage/organelle.as | 1065 ++ scripts/microbe_stage/organelle.lua | 550 - scripts/microbe_stage/organelle_component.as | 103 + scripts/microbe_stage/organelle_component.lua | 80 - scripts/microbe_stage/organelle_table.as | 514 + scripts/microbe_stage/organelle_table.lua | 228 - scripts/microbe_stage/procedural_microbes.as | 188 + scripts/microbe_stage/procedural_microbes.lua | 135 - scripts/microbe_stage/process_organelle.lua | 41 - scripts/microbe_stage/process_table.as | 89 + scripts/microbe_stage/process_table.lua | 68 - scripts/microbe_stage/processor_organelle.as | 39 + scripts/microbe_stage/setup.as | 485 + scripts/microbe_stage/setup.lua | 435 - scripts/microbe_stage/species_system.as | 743 + scripts/microbe_stage/species_system.lua | 440 - scripts/microbe_stage/storage_organelle.as | 54 + scripts/microbe_stage/storage_organelle.lua | 47 - .../tutorial}/microbe_stage_tutorial_hud.lua | 0 scripts/microbe_stage_tutorial/manifest.txt | 4 - scripts/microbe_stage_tutorial/setup.lua | 164 - scripts/script_system.as | 4 + scripts/win-update-scripts-and-run.bat | 6 - src/CMakeLists.txt | 221 +- src/Main.cpp | 86 - src/Main_Res.rc | 13 + src/ThriveGame.cpp | 1883 +++ src/ThriveGame.h | 139 + src/bullet/CMakeLists.txt | 20 - src/bullet/bullet_ogre_conversion.h | 47 - src/bullet/bullet_to_ogre_system.cpp | 71 - src/bullet/bullet_to_ogre_system.h | 74 - src/bullet/collision_filter.cpp | 146 - src/bullet/collision_filter.h | 185 - src/bullet/collision_shape.cpp | 683 - src/bullet/collision_shape.h | 425 - src/bullet/collision_system.cpp | 244 - src/bullet/collision_system.h | 263 - src/bullet/debug_drawing.cpp | 339 - src/bullet/debug_drawing.h | 223 - src/bullet/physical_world.cpp | 59 - src/bullet/physical_world.h | 46 - src/bullet/rigid_body_system.cpp | 550 - src/bullet/rigid_body_system.h | 461 - src/bullet/update_physics_system.cpp | 68 - src/bullet/update_physics_system.h | 65 - src/engine/CMakeLists.txt | 39 - src/engine/component.cpp | 60 - src/engine/component.h | 203 - src/engine/component_collection.cpp | 163 - src/engine/component_collection.h | 179 - src/engine/component_factory.cpp | 195 - src/engine/component_factory.h | 178 - src/engine/component_types.h | 35 + src/engine/engine.h | 414 - src/engine/entity.cpp | 294 - src/engine/entity.h | 316 - src/engine/entity_filter.cpp | 313 - src/engine/entity_filter.h | 246 - src/engine/entity_manager.cpp | 480 - src/engine/entity_manager.h | 485 - src/engine/game_state.cpp | 119 - src/engine/game_state.h | 110 - src/engine/player_data.cpp | 109 +- src/engine/player_data.h | 92 +- src/engine/rng.cpp | 104 - src/engine/rng.h | 140 - src/engine/serialization.cpp | 199 +- src/engine/serialization.h | 68 +- src/engine/system.cpp | 128 - src/engine/system.h | 184 - src/engine/touchable.cpp | 33 - src/engine/touchable.h | 124 - src/engine/typedefs.h | 11 +- src/game.cpp | 151 - src/game.h | 89 - src/general/CMakeLists.txt | 19 - src/general/hex.cpp | 149 +- src/general/hex.h | 69 +- src/general/json_registry.h | 175 + src/general/locked_map.cpp | 30 +- src/general/locked_map.h | 33 +- src/general/perlin_noise.cpp | 1 + src/general/timed_life_system.cpp | 112 +- src/general/timed_life_system.h | 91 +- src/gui/AlphaHitWindow.cpp | 230 - src/gui/AlphaHitWindow.h | 48 - src/gui/CEGUIVideoPlayer.cpp | 178 - src/gui/CEGUIVideoPlayer.h | 130 - src/gui/CEGUIWindow.cpp | 604 - src/gui/CEGUIWindow.h | 521 - src/gui/CMakeLists.txt | 17 - src/gui/VideoPlayer.cpp | 1273 -- src/gui/VideoPlayer.h | 130 - src/gui/cegui_types.h | 9 - src/gui/gui_texture_helper.cpp | 31 - src/gui/gui_texture_helper.h | 24 - src/gui/script_wrappers.cpp | 49 - src/gui/script_wrappers.h | 46 - src/main_menu_keypresses.cpp | 50 + src/main_menu_keypresses.h | 35 + src/microbe_stage/CMakeLists.txt | 26 - src/microbe_stage/agent_cloud_system.cpp | 260 +- src/microbe_stage/agent_cloud_system.h | 135 +- src/microbe_stage/bacteria_types.cpp | 47 + src/microbe_stage/bacteria_types.h | 31 + src/microbe_stage/bio_process_registry.cpp | 181 - src/microbe_stage/bio_process_registry.h | 141 - src/microbe_stage/biome_controller.cpp | 33 + src/microbe_stage/biome_controller.h | 24 + src/microbe_stage/biomes.cpp | 61 + src/microbe_stage/biomes.h | 44 + src/microbe_stage/bioprocesses.cpp | 31 + src/microbe_stage/bioprocesses.h | 22 + src/microbe_stage/compound.cpp | 127 - src/microbe_stage/compound.h | 128 - .../compound_absorber_system.cpp | 518 +- src/microbe_stage/compound_absorber_system.h | 340 +- src/microbe_stage/compound_cloud_system.cpp | 1131 +- src/microbe_stage/compound_cloud_system.h | 388 +- src/microbe_stage/compound_emitter_system.cpp | 303 - src/microbe_stage/compound_emitter_system.h | 227 - src/microbe_stage/compound_registry.cpp | 337 - src/microbe_stage/compound_registry.h | 299 - src/microbe_stage/compounds.cpp | 18 + src/microbe_stage/compounds.h | 21 + .../generate_cell_stage_world.rb | 166 + .../generate_microbe_editor_world.rb | 70 + src/microbe_stage/membrane_system.cpp | 975 +- src/microbe_stage/membrane_system.h | 339 +- src/microbe_stage/microbe_camera_system.cpp | 90 +- src/microbe_stage/microbe_camera_system.h | 77 +- src/microbe_stage/organelle_types.cpp | 30 + src/microbe_stage/organelle_types.h | 32 + src/microbe_stage/player_microbe_control.cpp | 243 + src/microbe_stage/player_microbe_control.h | 85 + src/microbe_stage/process_system.cpp | 494 +- src/microbe_stage/process_system.h | 127 +- src/microbe_stage/simulation_parameters.cpp | 44 + src/microbe_stage/simulation_parameters.h | 35 + src/microbe_stage/spawn_system.cpp | 354 +- src/microbe_stage/spawn_system.h | 162 +- src/microbe_stage/species.cpp | 32 + src/microbe_stage/species.h | 27 + src/microbe_stage/species_component.cpp | 133 +- src/microbe_stage/species_component.h | 39 +- src/microbe_stage/species_name_controller.cpp | 29 + src/microbe_stage/species_name_controller.h | 19 + src/ogre/CMakeLists.txt | 28 - src/ogre/camera_system.cpp | 226 - src/ogre/camera_system.h | 212 - src/ogre/colour_material.cpp | 39 - src/ogre/colour_material.h | 17 - src/ogre/keyboard.cpp | 360 - src/ogre/keyboard.h | 175 - src/ogre/light_system.cpp | 216 - src/ogre/light_system.h | 210 - src/ogre/membrane_generation_system.cpp | 548 - src/ogre/membrane_generation_system.h | 121 - src/ogre/mouse.cpp | 245 - src/ogre/mouse.h | 156 - src/ogre/render_system.cpp | 67 - src/ogre/render_system.h | 69 - src/ogre/scene_node_system.cpp | 596 - src/ogre/scene_node_system.h | 376 - src/ogre/sky_system.cpp | 174 - src/ogre/sky_system.h | 173 - src/ogre/workspace_system.cpp | 359 - src/ogre/workspace_system.h | 176 - src/resource.h | 2 + src/scripting/CMakeLists.txt | 14 - src/scripting/luajit.h | 51 - src/scripting/script_entity_filter.cpp | 229 - src/scripting/script_entity_filter.h | 136 - src/scripting/script_helpers.h | 35 - src/scripting/script_wrapper.h | 25 - src/scripting/wrapper_classes.cpp | 88 - src/scripting/wrapper_classes.h | 52 - src/sound/CMakeLists.txt | 18 - src/sound/caudio_include.h | 41 - src/sound/node_attachable.cpp | 134 - src/sound/node_attachable.h | 46 - src/sound/sound_emitter.cpp | 202 - src/sound/sound_emitter.h | 84 - src/sound/sound_listener.cpp | 77 - src/sound/sound_listener.h | 34 - src/sound/sound_manager.cpp | 232 - src/sound/sound_manager.h | 99 - src/sound/sound_memory_stream.cpp | 262 - src/sound/sound_memory_stream.h | 150 - src/sound/sound_source_system.cpp | 725 - src/sound/sound_source_system.h | 378 - src/thrive_net_handler.cpp | 43 + src/thrive_net_handler.h | 30 + src/thrive_world_factory.cpp | 30 + src/thrive_world_factory.h | 21 + src/util/CMakeLists.txt | 5 - src/util/make_unique.h | 11 - test/CMakeLists.txt | 2 + {src/engine/tests => test}/engine.cpp | 0 {src/engine/tests => test}/entity.cpp | 0 {src/engine/tests => test}/entity_filter.cpp | 0 {src/engine/tests => test}/rng.cpp | 0 {src/engine/tests => test}/rolling_grid.cpp | 0 {src/ogre/tests => test}/script_bindings.cpp | 0 {src/engine/tests => test}/serialization.cpp | 0 {src/ogre/tests => test}/sky_system.cpp | 0 {src/engine/tests => test}/test_component.h | 0 thriveversion.ver | 1 - windows/cmake_modules/FindBullet.cmake | 84 - windows/thrive.rc | 1 - 377 files changed, 20409 insertions(+), 57540 deletions(-) create mode 100644 .clang-format create mode 100755 QuickRecompile.rb create mode 160000 RubySetupSystem delete mode 100644 cmake_modules/FindBoost.cmake delete mode 100644 cmake_modules/FindCEGUI.cmake delete mode 100644 cmake_modules/FindFFMPEG.cmake delete mode 100644 cmake_modules/FindFreetype.cmake delete mode 100644 cmake_modules/FindOGRE.cmake delete mode 100644 cmake_modules/FindOIS.cmake delete mode 100644 cmake_modules/FindOgg.cmake delete mode 100644 cmake_modules/FindOgreFFMPEG.cmake delete mode 100644 cmake_modules/FindOpenAL.cmake delete mode 100644 cmake_modules/FindPackageHelper.cmake delete mode 100644 cmake_modules/FindPkgMacros.cmake delete mode 100644 cmake_modules/FindTinyXML.cmake delete mode 100644 cmake_modules/FindVorbis.cmake delete mode 100644 cmake_modules/FindcAudio.cmake delete mode 100644 cmake_modules/FindirrKlang.cmake delete mode 100644 cmake_modules/LibFindMacros.cmake delete mode 100644 cmake_modules/LibraryPathHints.cmake delete mode 100644 cmake_modules/PreprocessorUtils.cmake delete mode 100644 cmake_modules/add_to_project.cmake delete mode 100644 cmake_modules/compiler_flags.cmake delete mode 100644 cmake_modules/findMyGUI.cmake delete mode 100644 cmake_modules/utils.cmake delete mode 160000 contrib/googletest delete mode 100644 contrib/lua/building.txt delete mode 160000 contrib/lua/luajit delete mode 100755 contrib/lua/sol.hpp delete mode 100644 contrib/lua/sol_changes.txt create mode 100644 doc/angelscript_primer.md create mode 100644 doc/clang_format.md delete mode 100644 doc/engine_overview.dox create mode 100644 doc/engine_overview.md delete mode 100644 doc/entity_component.dox create mode 100644 doc/entity_component.md delete mode 100644 doc/lua_primer.dox delete mode 100644 doc/main.dox delete mode 100644 doc/scripting.dox create mode 100644 doc/setup_instructions.md rename doc/{style_guide.dox => style_guide.md} (55%) delete mode 100644 linux_setup/DepGlobber.rb delete mode 100644 linux_setup/RubyCommon.rb delete mode 100644 linux_setup/RubySetupSystem.rb delete mode 100755 linux_setup/RunCodeIndexing.rb delete mode 100644 linux_setup/WinInstall.rb delete mode 100644 linux_setup/readme.md delete mode 100644 mingw_setup/.gitignore delete mode 100644 mingw_setup/7zip/install.ps1 delete mode 100644 mingw_setup/OpenAL/install.ps1 delete mode 100644 mingw_setup/OpenAL/install.sh delete mode 100644 mingw_setup/TinyXML/CMakeLists.txt delete mode 100644 mingw_setup/TinyXML/TODO-ADD-SH delete mode 100644 mingw_setup/TinyXML/install.ps1 delete mode 100644 mingw_setup/boost/install.ps1 delete mode 100755 mingw_setup/boost/install.sh delete mode 100644 mingw_setup/bullet/install.ps1 delete mode 100755 mingw_setup/bullet/install.sh delete mode 100644 mingw_setup/cAudio/install.ps1 delete mode 100644 mingw_setup/cegui/install.ps1 delete mode 100644 mingw_setup/cegui/install.sh delete mode 100644 mingw_setup/cegui_dependencies/install.ps1 delete mode 100644 mingw_setup/cegui_dependencies/install.sh delete mode 100644 mingw_setup/cmake/install.ps1 delete mode 100644 mingw_setup/cmake/install.sh delete mode 100644 mingw_setup/configure_toolchain.cmake delete mode 100644 mingw_setup/ffmpeg/install.ps1 delete mode 100644 mingw_setup/gtest/install.ps1 delete mode 100755 mingw_setup/gtest/install.sh delete mode 100644 mingw_setup/lua51.dll delete mode 100644 mingw_setup/luajit.exe delete mode 100644 mingw_setup/luajit/install.ps1 delete mode 100644 mingw_setup/mingw/install.ps1 delete mode 100755 mingw_setup/mingw/install.sh delete mode 100644 mingw_setup/ogg/CMakeLists.txt delete mode 100644 mingw_setup/ogg/install.ps1 delete mode 100755 mingw_setup/ogg/install.sh delete mode 100644 mingw_setup/ogre/install.ps1 delete mode 100755 mingw_setup/ogre/install.sh delete mode 100644 mingw_setup/ogre_dependencies/install.ps1 delete mode 100755 mingw_setup/ogre_dependencies/install.sh delete mode 100644 mingw_setup/readme.txt delete mode 100644 mingw_setup/setup-logged.ps1 delete mode 100644 mingw_setup/setup-logged.sh delete mode 100644 mingw_setup/setup.ps1 delete mode 100755 mingw_setup/setup.sh delete mode 100644 mingw_setup/toolchain_linux.cmake.in delete mode 100644 mingw_setup/toolchain_win.cmake.in delete mode 100644 mingw_setup/utils.ps1 delete mode 100644 mingw_setup/utils.sh delete mode 100644 mingw_setup/vorbis/CMakeLists.txt delete mode 100644 mingw_setup/vorbis/install.ps1 delete mode 100755 mingw_setup/vorbis/install.sh delete mode 100644 ogre_cfg/plugins.cfg delete mode 100644 ogre_cfg/plugins_d.cfg delete mode 100644 ogre_cfg/resources.cfg create mode 100644 scripts/SimulationParameters/MicrobeStage/Bacteria.json create mode 100644 scripts/SimulationParameters/MicrobeStage/BioProcesses.json create mode 100644 scripts/SimulationParameters/MicrobeStage/Biomes.json create mode 100644 scripts/SimulationParameters/MicrobeStage/Compounds.json create mode 100644 scripts/SimulationParameters/MicrobeStage/Organelles.json create mode 100644 scripts/SimulationParameters/MicrobeStage/Species.json create mode 100644 scripts/SimulationParameters/MicrobeStage/SpeciesNames.json create mode 100644 scripts/SimulationParameters/MicrobeStage/StartingCompounds.json delete mode 100644 scripts/class.lua delete mode 100644 scripts/constants.lua delete mode 100644 scripts/game.lua create mode 100644 scripts/gui/MainMenu.layout create mode 100644 scripts/gui/gui_common.js create mode 100644 scripts/gui/main_menu.js create mode 100644 scripts/gui/microbe_gui_events.as create mode 100644 scripts/gui/thrive_gui.html create mode 100644 scripts/gui/thrive_menus.txt create mode 100644 scripts/gui/thrive_style.css delete mode 100644 scripts/lua_engine/game_state.lua delete mode 100644 scripts/lua_engine/keymap.lua delete mode 100644 scripts/lua_engine/lua_engine.lua delete mode 100644 scripts/lua_engine/manifest.txt delete mode 100644 scripts/lua_engine/system.lua delete mode 100644 scripts/lua_notes.md delete mode 100644 scripts/main_menu/main_menu_hud.lua delete mode 100644 scripts/main_menu/manifest.txt delete mode 100644 scripts/main_menu/setup.lua delete mode 100644 scripts/manifest.txt delete mode 100644 scripts/microbe_editor/manifest.txt create mode 100644 scripts/microbe_editor/microbe_editor.as create mode 100644 scripts/microbe_editor/microbe_editor.levgm delete mode 100644 scripts/microbe_editor/microbe_editor.lua create mode 100644 scripts/microbe_editor/microbe_editor_hud.as delete mode 100644 scripts/microbe_editor/microbe_editor_hud.lua create mode 100644 scripts/microbe_editor/setup.as delete mode 100644 scripts/microbe_editor/setup.lua create mode 100644 scripts/microbe_stage/agent_vacuole.as delete mode 100644 scripts/microbe_stage/agent_vacuole.lua create mode 100644 scripts/microbe_stage/agents.as delete mode 100644 scripts/microbe_stage/bacteria_system.lua delete mode 100644 scripts/microbe_stage/bacteria_table.lua create mode 100644 scripts/microbe_stage/biome.as delete mode 100644 scripts/microbe_stage/biome.lua delete mode 100644 scripts/microbe_stage/biome_table.lua delete mode 100644 scripts/microbe_stage/compound_table.lua create mode 100644 scripts/microbe_stage/configs.as delete mode 100644 scripts/microbe_stage/configs.lua create mode 100644 scripts/microbe_stage/hex.as delete mode 100644 scripts/microbe_stage/hex.lua delete mode 100644 scripts/microbe_stage/manifest.txt create mode 100644 scripts/microbe_stage/microbe.as delete mode 100644 scripts/microbe_stage/microbe.lua create mode 100644 scripts/microbe_stage/microbe_ai.as delete mode 100644 scripts/microbe_stage/microbe_ai.lua delete mode 100644 scripts/microbe_stage/microbe_control.lua create mode 100644 scripts/microbe_stage/microbe_operations.as create mode 100644 scripts/microbe_stage/microbe_stage.levgm create mode 100644 scripts/microbe_stage/microbe_stage_hud.as delete mode 100644 scripts/microbe_stage/microbe_stage_hud.lua create mode 100644 scripts/microbe_stage/movement_organelle.as delete mode 100644 scripts/microbe_stage/movement_organelle.lua create mode 100644 scripts/microbe_stage/nucleus_organelle.as delete mode 100644 scripts/microbe_stage/nucleus_organelle.lua create mode 100644 scripts/microbe_stage/organelle.as delete mode 100644 scripts/microbe_stage/organelle.lua create mode 100644 scripts/microbe_stage/organelle_component.as delete mode 100644 scripts/microbe_stage/organelle_component.lua create mode 100644 scripts/microbe_stage/organelle_table.as delete mode 100644 scripts/microbe_stage/organelle_table.lua create mode 100644 scripts/microbe_stage/procedural_microbes.as delete mode 100644 scripts/microbe_stage/procedural_microbes.lua delete mode 100644 scripts/microbe_stage/process_organelle.lua create mode 100644 scripts/microbe_stage/process_table.as delete mode 100644 scripts/microbe_stage/process_table.lua create mode 100644 scripts/microbe_stage/processor_organelle.as create mode 100644 scripts/microbe_stage/setup.as delete mode 100644 scripts/microbe_stage/setup.lua create mode 100644 scripts/microbe_stage/species_system.as delete mode 100644 scripts/microbe_stage/species_system.lua create mode 100644 scripts/microbe_stage/storage_organelle.as delete mode 100644 scripts/microbe_stage/storage_organelle.lua rename scripts/{microbe_stage_tutorial => microbe_stage/tutorial}/microbe_stage_tutorial_hud.lua (100%) delete mode 100644 scripts/microbe_stage_tutorial/manifest.txt delete mode 100644 scripts/microbe_stage_tutorial/setup.lua create mode 100644 scripts/script_system.as delete mode 100644 scripts/win-update-scripts-and-run.bat delete mode 100644 src/Main.cpp create mode 100644 src/Main_Res.rc create mode 100644 src/ThriveGame.cpp create mode 100644 src/ThriveGame.h delete mode 100644 src/bullet/CMakeLists.txt delete mode 100644 src/bullet/bullet_ogre_conversion.h delete mode 100644 src/bullet/bullet_to_ogre_system.cpp delete mode 100644 src/bullet/bullet_to_ogre_system.h delete mode 100644 src/bullet/collision_filter.cpp delete mode 100644 src/bullet/collision_filter.h delete mode 100644 src/bullet/collision_shape.cpp delete mode 100644 src/bullet/collision_shape.h delete mode 100644 src/bullet/collision_system.cpp delete mode 100644 src/bullet/collision_system.h delete mode 100644 src/bullet/debug_drawing.cpp delete mode 100644 src/bullet/debug_drawing.h delete mode 100644 src/bullet/physical_world.cpp delete mode 100644 src/bullet/physical_world.h delete mode 100644 src/bullet/rigid_body_system.cpp delete mode 100644 src/bullet/rigid_body_system.h delete mode 100644 src/bullet/update_physics_system.cpp delete mode 100644 src/bullet/update_physics_system.h delete mode 100644 src/engine/CMakeLists.txt delete mode 100644 src/engine/component.cpp delete mode 100644 src/engine/component.h delete mode 100644 src/engine/component_collection.cpp delete mode 100644 src/engine/component_collection.h delete mode 100644 src/engine/component_factory.cpp delete mode 100644 src/engine/component_factory.h create mode 100644 src/engine/component_types.h delete mode 100644 src/engine/engine.h delete mode 100644 src/engine/entity.cpp delete mode 100644 src/engine/entity.h delete mode 100644 src/engine/entity_filter.cpp delete mode 100644 src/engine/entity_filter.h delete mode 100644 src/engine/entity_manager.cpp delete mode 100644 src/engine/entity_manager.h delete mode 100644 src/engine/game_state.cpp delete mode 100644 src/engine/game_state.h delete mode 100644 src/engine/rng.cpp delete mode 100644 src/engine/rng.h delete mode 100644 src/engine/system.cpp delete mode 100644 src/engine/system.h delete mode 100644 src/engine/touchable.cpp delete mode 100644 src/engine/touchable.h delete mode 100644 src/game.cpp delete mode 100644 src/game.h delete mode 100644 src/general/CMakeLists.txt create mode 100644 src/general/json_registry.h delete mode 100644 src/gui/AlphaHitWindow.cpp delete mode 100644 src/gui/AlphaHitWindow.h delete mode 100644 src/gui/CEGUIVideoPlayer.cpp delete mode 100644 src/gui/CEGUIVideoPlayer.h delete mode 100644 src/gui/CEGUIWindow.cpp delete mode 100644 src/gui/CEGUIWindow.h delete mode 100644 src/gui/CMakeLists.txt delete mode 100644 src/gui/VideoPlayer.cpp delete mode 100644 src/gui/VideoPlayer.h delete mode 100644 src/gui/cegui_types.h delete mode 100644 src/gui/gui_texture_helper.cpp delete mode 100644 src/gui/gui_texture_helper.h delete mode 100644 src/gui/script_wrappers.cpp delete mode 100644 src/gui/script_wrappers.h create mode 100644 src/main_menu_keypresses.cpp create mode 100644 src/main_menu_keypresses.h delete mode 100644 src/microbe_stage/CMakeLists.txt create mode 100644 src/microbe_stage/bacteria_types.cpp create mode 100644 src/microbe_stage/bacteria_types.h delete mode 100644 src/microbe_stage/bio_process_registry.cpp delete mode 100644 src/microbe_stage/bio_process_registry.h create mode 100644 src/microbe_stage/biome_controller.cpp create mode 100644 src/microbe_stage/biome_controller.h create mode 100644 src/microbe_stage/biomes.cpp create mode 100644 src/microbe_stage/biomes.h create mode 100644 src/microbe_stage/bioprocesses.cpp create mode 100644 src/microbe_stage/bioprocesses.h delete mode 100644 src/microbe_stage/compound.cpp delete mode 100644 src/microbe_stage/compound.h delete mode 100644 src/microbe_stage/compound_emitter_system.cpp delete mode 100644 src/microbe_stage/compound_emitter_system.h delete mode 100644 src/microbe_stage/compound_registry.cpp delete mode 100644 src/microbe_stage/compound_registry.h create mode 100644 src/microbe_stage/compounds.cpp create mode 100644 src/microbe_stage/compounds.h create mode 100644 src/microbe_stage/generate_cell_stage_world.rb create mode 100644 src/microbe_stage/generate_microbe_editor_world.rb create mode 100644 src/microbe_stage/organelle_types.cpp create mode 100644 src/microbe_stage/organelle_types.h create mode 100644 src/microbe_stage/player_microbe_control.cpp create mode 100644 src/microbe_stage/player_microbe_control.h create mode 100644 src/microbe_stage/simulation_parameters.cpp create mode 100644 src/microbe_stage/simulation_parameters.h create mode 100644 src/microbe_stage/species.cpp create mode 100644 src/microbe_stage/species.h create mode 100644 src/microbe_stage/species_name_controller.cpp create mode 100644 src/microbe_stage/species_name_controller.h delete mode 100644 src/ogre/CMakeLists.txt delete mode 100644 src/ogre/camera_system.cpp delete mode 100644 src/ogre/camera_system.h delete mode 100644 src/ogre/colour_material.cpp delete mode 100644 src/ogre/colour_material.h delete mode 100644 src/ogre/keyboard.cpp delete mode 100644 src/ogre/keyboard.h delete mode 100644 src/ogre/light_system.cpp delete mode 100644 src/ogre/light_system.h delete mode 100644 src/ogre/membrane_generation_system.cpp delete mode 100644 src/ogre/membrane_generation_system.h delete mode 100644 src/ogre/mouse.cpp delete mode 100644 src/ogre/mouse.h delete mode 100644 src/ogre/render_system.cpp delete mode 100644 src/ogre/render_system.h delete mode 100644 src/ogre/scene_node_system.cpp delete mode 100644 src/ogre/scene_node_system.h delete mode 100644 src/ogre/sky_system.cpp delete mode 100644 src/ogre/sky_system.h delete mode 100644 src/ogre/workspace_system.cpp delete mode 100644 src/ogre/workspace_system.h create mode 100644 src/resource.h delete mode 100644 src/scripting/CMakeLists.txt delete mode 100644 src/scripting/luajit.h delete mode 100644 src/scripting/script_entity_filter.cpp delete mode 100644 src/scripting/script_entity_filter.h delete mode 100644 src/scripting/script_helpers.h delete mode 100644 src/scripting/script_wrapper.h delete mode 100644 src/scripting/wrapper_classes.cpp delete mode 100644 src/scripting/wrapper_classes.h delete mode 100644 src/sound/CMakeLists.txt delete mode 100644 src/sound/caudio_include.h delete mode 100644 src/sound/node_attachable.cpp delete mode 100644 src/sound/node_attachable.h delete mode 100644 src/sound/sound_emitter.cpp delete mode 100644 src/sound/sound_emitter.h delete mode 100644 src/sound/sound_listener.cpp delete mode 100644 src/sound/sound_listener.h delete mode 100644 src/sound/sound_manager.cpp delete mode 100644 src/sound/sound_manager.h delete mode 100644 src/sound/sound_memory_stream.cpp delete mode 100644 src/sound/sound_memory_stream.h delete mode 100644 src/sound/sound_source_system.cpp delete mode 100644 src/sound/sound_source_system.h create mode 100644 src/thrive_net_handler.cpp create mode 100644 src/thrive_net_handler.h create mode 100644 src/thrive_world_factory.cpp create mode 100644 src/thrive_world_factory.h delete mode 100644 src/util/CMakeLists.txt delete mode 100644 src/util/make_unique.h create mode 100644 test/CMakeLists.txt rename {src/engine/tests => test}/engine.cpp (100%) rename {src/engine/tests => test}/entity.cpp (100%) rename {src/engine/tests => test}/entity_filter.cpp (100%) rename {src/engine/tests => test}/rng.cpp (100%) rename {src/engine/tests => test}/rolling_grid.cpp (100%) rename {src/ogre/tests => test}/script_bindings.cpp (100%) rename {src/engine/tests => test}/serialization.cpp (100%) rename {src/ogre/tests => test}/sky_system.cpp (100%) rename {src/engine/tests => test}/test_component.h (100%) delete mode 100644 thriveversion.ver delete mode 100644 windows/cmake_modules/FindBullet.cmake delete mode 100644 windows/thrive.rc diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000000..d7f5caf8cc6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,75 @@ +--- +Language: Cpp +AccessModifierOffset: '-4' +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: 'false' +AlignConsecutiveDeclarations: 'false' +AlignEscapedNewlinesLeft: Left +AlignTrailingComments: 'false' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortBlocksOnASingleLine: 'false' +AllowShortCaseLabelsOnASingleLine: 'true' +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +AlwaysBreakAfterReturnType: All +AlwaysBreakBeforeMultilineStrings: 'false' +AlwaysBreakTemplateDeclarations: 'false' +BinPackArguments: 'true' +BinPackParameters: 'false' +BreakBeforeBinaryOperators: None +# BreakBeforeBraces: Attach +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterStruct: false + AfterUnion: false + # AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: false + SplitEmptyNamespace: true +BreakBeforeInheritanceComma: 'false' +BreakBeforeTernaryOperators: 'false' +BreakConstructorInitializers: AfterColon +# Works fine even without this +# CommentPragmas: '^! \\' +CompactNamespaces: 'true' +ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' +Cpp11BracedListStyle: 'true' +DerivePointerAlignment: 'false' +IndentCaseLabels: 'false' +IndentWidth: '4' +IndentWrappedFunctionNames: 'true' +KeepEmptyLinesAtTheStartOfBlocks: 'true' +MaxEmptyLinesToKeep: '3' +NamespaceIndentation: None +PointerAlignment: Left +ReflowComments: 'true' +SortIncludes: 'true' +SortUsingDeclarations: 'true' +SpaceAfterCStyleCast: 'false' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeParens: Never +# This is also a new setting not yet available +# SpaceBeforeRangeBasedForLoopColon: 'true' +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' +Standard: Cpp11 +TabWidth: '4' +UseTab: Never + +... diff --git a/.gitignore b/.gitignore index b01b0fff30c..d20612c4782 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,15 @@ # Asset directory assets/* +# autogenerated file +/src/thrive_version.h +/src/main.cpp +/src/generated + # asset symlinks -/cegui_examples -/definitions -/fonts -/gui -/materials -/models -/sounds -/videos +/Fonts +/Textures + # ue4 stuff .svn @@ -119,4 +119,4 @@ nbproject/ # Cscope files /cscope.files -/RunCodeIndexing.rb \ No newline at end of file +/RunCodeIndexing.rb diff --git a/.gitmodules b/.gitmodules index a680cdbe3c6..7cecc5d2f7c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "contrib/googletest"] - path = contrib/googletest - url = git://github.com/liquid-mirror/googletest.git -[submodule "contrib/lua/luajit"] - path = contrib/lua/luajit - url = http://luajit.org/git/luajit-2.0.git +[submodule "RubySetupSystem"] + path = RubySetupSystem + url = https://github.com/hhyyrylainen/RubySetupSystem.git diff --git a/CMakeLists.txt b/CMakeLists.txt index b6b7b293ff3..46f3c85e155 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,10 @@ # http://www.ogre3d.org/tikiwiki/ # # Modified as part of the Thrive project +# As of the Leviathan engine update this has been mostly rewritten #----------------------------------------------------------------------------- -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.0) project(Thrive) @@ -14,323 +15,204 @@ project(Thrive) # Cache Variables # ################### -# Ogre SDK -SET(OGRE_SDK "" - CACHE STRING "Path to the Ogre SDK" -) - set(ASSET_DIRECTORY "${CMAKE_SOURCE_DIR}/assets" - CACHE PATH "Path to assets" -) + CACHE PATH "Path to assets" + ) + +# This isn't really meant to be modified +set(LEVIATHAN_SRC "${PROJECT_SOURCE_DIR}/ThirdParty/Leviathan" CACHE FILEPATH + "Path to leviathan source folder") if(NOT IS_DIRECTORY "${ASSET_DIRECTORY}/models") message(FATAL_ERROR "Could not find assets in ${ASSET_DIRECTORY}. -Please use Subversion to download the assets: - svn co http://assets.revolutionarygamesstudio.com/ ${ASSET_DIRECTORY} +Please run the SetupThrive.rb script to download them. Use 'thrive' for the username and password " ) endif() -############### -# CMake Setup # -############### - -# Configure search path for cmake modules -list(APPEND CMAKE_MODULE_PATH - "${CMAKE_SOURCE_DIR}/cmake_modules" -) - -if(WIN32) - list(APPEND CMAKE_MODULE_PATH - "${CMAKE_SOURCE_DIR}/windows/cmake_modules") -endif() - -# Import utility functions -include(add_to_project) -include(utils) - -# Search path for dynamic libraries at runtime. Only relevant for Linux. -set(CMAKE_INSTALL_RPATH ".:$ORIGIN") - -# Makes sure that the RPATH is always the install path. Required for linux -# redistributable -SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - -# Assure a proper build type -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE - "Debug" - CACHE STRING "Choose the type of build, options are: None (CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo." - FORCE - ) -endif () - -# Install into dist subdirectory -set(CMAKE_INSTALL_PREFIX - "${CMAKE_CURRENT_BINARY_DIR}/dist" - CACHE STRING "Install path" FORCE -) - +########### +# Options # +########### -############# -# Find OGRE # -############# +option(USE_BREAKPAD "For enabling breakpad crash handling, set off for local debugging" OFF) +option(COPY_BOOST_TO_PACKAGE "If on copies all boost libraries to package" ON) +option(STRIP_SYMBOLS_ON_INSTALL "For stripping debug symbols on install" ON) -find_package(OGRE REQUIRED) -# OGRE Plugins used -set(OGRE_PLUGINS - # Plugin_BSPSceneManager - # Plugin_OctreeSceneManager - # Plugin_OctreeZone - Plugin_ParticleFX - # Plugin_CgProgramManager - # Plugin_PCZSceneManager - RenderSystem_GL -) +########################### +# Leviathan Project Setup # +########################### +# Set up cmake modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/CMake" + "${LEVIATHAN_SRC}/CMake" + "${LEVIATHAN_SRC}/LeviathanCMake") -####### -# OIS # -####### +set(LEVIATHAN_SKIP_OPTIONAL_ASSETS ON) -find_package(OIS REQUIRED QUIET) +include(LeviathanCompileOptions) +include(LeviathanSetRPath) +set(LEVIATHAN_FULL_BUILD ON) -############## -# Find Boost # -############## - -set(BOOST_COMPONENTS - chrono - date_time - filesystem - thread - system - atomic -) +set(USE_ANGELSCRIPT ON) +set(USE_BOOST ON) +set(USE_OGRE ON) +set(USE_NEWTON ON) +set(USE_SFML ON) +set(USE_SDL2 ON) -find_package(Boost COMPONENTS ${BOOST_COMPONENTS} REQUIRED QUIET) +include(LeviathanFindLibraries) -############### -# Google Test # -############### +include(LeviathanUtility) -add_subdirectory( - "${CMAKE_CURRENT_SOURCE_DIR}/contrib/googletest" -) - -include_directories( - SYSTEM - "${CMAKE_CURRENT_SOURCE_DIR}/contrib/googletest/include" -) +# Leviathan Required settings +set(CMAKE_INSTALL_PREFIX "./Install" CACHE FILEPATH "Install path") -########## -# Bullet # -########## +DefinePreprocessorMacro(USE_BREAKPAD LEVIATHAN_USING_BREAKPAD) -find_package(Bullet REQUIRED QUIET) +include(LeviathanDefaultFileCopy) +include(LeviathanSetRPath) -include_directories(SYSTEM ${BULLET_INCLUDE_DIRS}) - -####### -# Lua # -####### - -option(LUA_CHECKS "when ON enables additional Lua safety - checks. Lowers performance so only use while debugging" - OFF) - -if(LUA_CHECKS) - - add_definitions(-DSOL_CHECK_ARGUMENTS) - +# -Wl,-rpath-link is used to suppress warnings from games linking gainst libEngine.so +if(UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-rpath-link,${CMAKE_BINARY_DIR}/bin/lib") endif() -include_directories( - "${CMAKE_CURRENT_SOURCE_DIR}/contrib/lua" - ) - -link_directories( - "${CMAKE_CURRENT_SOURCE_DIR}/contrib/lua/luajit/src" - "${CMAKE_CURRENT_SOURCE_DIR}/mingw_setup" - ) - -set(LUA_FOUND TRUE) +# Links to libs +# Copy engine lib if(WIN32) - set(LUA_LIBRARIES lua51.dll) + file(COPY "${LEVIATHAN_SRC}/build/bin/Engine.dll" DESTINATION "${CMAKE_BINARY_DIR}/bin") + file(COPY "${LEVIATHAN_SRC}/build/bin/Engine.pdb" DESTINATION "${CMAKE_BINARY_DIR}/bin") else() - set(LUA_LIBRARIES luajit.a dl) + file(COPY "${LEVIATHAN_SRC}/build/bin/libEngine.so" DESTINATION "${CMAKE_BINARY_DIR}/bin") endif() +# Link own bin directory +link_directories("${CMAKE_BINARY_DIR}/bin") -####### -# CEGUI # -####### - -set(FIND_CEGUI_VERSION 9999) - -message(STATUS "Finding CEGUI version " ${FIND_CEGUI_VERSION} - " for Ogre version " ${OGRE_VERSION}) +# And engine +link_directories("${LEVIATHAN_SRC}/build/bin") -find_package(CEGUI REQUIRED QUIET COMPONENTS OGRE) +# Version +set(PROGRAM_VERSION_STABLE 0) +set(PROGRAM_VERSION_MAJOR 0) +set(PROGRAM_VERSION_MINOR 4) +set(PROGRAM_VERSION_PATCH 0) +set(PROGRAM_VERSION_STR ${PROGRAM_VERSION_STABLE}.${PROGRAM_VERSION_MAJOR}.${PROGRAM_VERSION_MINOR}.${PROGRAM_VERSION_PATCH}) +set(PROGRAM_VERSION ${PROGRAM_VERSION_STABLE}.${PROGRAM_VERSION_MAJOR}${PROGRAM_VERSION_MINOR}${PROGRAM_VERSION_PATCH}) -#set(CEGUI_INCLUDE_DIR -include_directories(SYSTEM ${CEGUI_INCLUDE_DIR}) +set(PROGRAM_VERSIONS "\"${PROGRAM_VERSION_STR}\"") +set(PROGRAM_VERSIONS_ANSI "\"${PROGRAM_VERSION_STR}\"") +set(ENGINECONFIGURATION "./EngineConf.conf") +set(GAMENAMEIDENTIFICATION Thrive) +set(GAMEVERSIONIDENTIFICATION GAME_VERSIONS) +set(ProgramNamespace thrive) +# Currently there is no master server +# set(PROGRAMMASTERSERVERINFO "MasterServerInformation(\"ThriveMasters.txt\", \"Thrive_\" GAME_VERSIONS, \"http://revolutionarygamesstudio.com/\", \"/Thrive/MastersList.png\", \"ThriveAccountCrecentials.txt\", false)") +set(PROGRAMMASTERSERVERINFO "MasterServerInformation()") -####### -# TinyXML # -####### +# Include dirs +include_directories("${LEVIATHAN_SRC}/Engine") -find_package(TinyXML REQUIRED QUIET) +set(DEPENDENT_LIBS ${LEVIATHAN_APPLICATION_LIBRARIES}) -include_directories(SYSTEM ${TINYXML_INCLUDE_DIR}) -################ -# cAudio # -################ +# Thrive compile setup +if(NOT WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-function -Wno-error=redundant-decls") +endif() +include_directories( + "${CMAKE_CURRENT_SOURCE_DIR}/src" +) -find_package(cAudio) -find_package(OpenAL QUIET) +add_subdirectory(src) -include_directories("${cAudio_INCLUDE_DIRS}") +add_subdirectory(test) -################ -# Ogre FFMPEG # -################ -find_package(FFMPEG) -#find_package(OgreFFMPEG) -#include_directories("${OgreFFMPEG_INCLUDE_DIR}") -include_directories("${FFMPEG_INCLUDE_DIRS}") +# Set the main executable as the startup project +set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY + VS_STARTUP_PROJECT Thrive) -###################### -# Configure Compiler # -###################### +# Copy script files to the bin folder +file(GLOB THRIVE_SCRIPTS "scripts/*") +file(COPY ${THRIVE_SCRIPTS} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Scripts") -include_directories(SYSTEM - ${Boost_INCLUDE_DIRS} - ${OIS_INCLUDE_DIRS} - ${OGRE_INCLUDE_DIRS} -) +# Copy other data assets +file(GLOB THRIVE_LOOKNFEEL "assets/gui/looknfeel/*") +file(COPY ${THRIVE_LOOKNFEEL} DESTINATION + "${PROJECT_BINARY_DIR}/bin/Data/Scripts/gui/looknfeel") -include_directories( - "${CMAKE_CURRENT_SOURCE_DIR}/src" -) +file(GLOB THRIVE_ANIMATIONS "assets/gui/animations/*") +file(COPY ${THRIVE_ANIMATIONS} DESTINATION + "${PROJECT_BINARY_DIR}/bin/Data/Scripts/gui/animations") -# Compile using c++11 and using sse2 -#no-unused-variable is necessary to supress werror while compiling cAudio -# SOL uses a bunch of recursive templates so unless all lua bindings are written to be -# less efficient runtime dynamic bindings we need to have bigger template depth. -# though this may kill compile times -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -msse2 -Wno-unused-function -Wno-error=redundant-decls -ftemplate-depth=1500" ) +file(GLOB THRIVE_TEXTURES "assets/textures/*") +file(COPY ${THRIVE_TEXTURES} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Textures/") +file(GLOB THRIVE_GUI_TEXTURES "assets/gui/imagesets/*") +file(COPY ${THRIVE_GUI_TEXTURES} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Textures/gui/") -find_package(Threads) +file(GLOB THRIVE_FONTS "assets/fonts/*") +file(COPY ${THRIVE_FONTS} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Fonts/") -################## -# Compile Thrive # -################## -# Collect sources from sub directories -add_subdirectory(src) -get_property(SOURCE_FILES GLOBAL PROPERTY SOURCE_FILES) +file(GLOB THRIVE_MATERIALS "assets/materials/*") +file(COPY ${THRIVE_MATERIALS} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Materials/") -# Set extensive warning flags -include(compiler_flags) -set_source_files_properties( - ${SOURCE_FILES} - PROPERTIES COMPILE_FLAGS ${WARNING_FLAGS} -) +file(GLOB THRIVE_MODELS "assets/models/*") +file(COPY ${THRIVE_MODELS} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Models/") -# Compile library -add_library(ThriveLib STATIC ${SOURCE_FILES}) - -target_link_libraries(ThriveLib - #These two FFMPEG need to be at the top (before ogre?) to avoid linking error - ${OgreFFMPEG_LIBRARIES} - ${FFMPEG_LIBRARIES} - ${Boost_LIBRARIES} - ${OGRE_LIBRARIES} - ${OIS_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - ${BULLET_LIBRARIES} - ${CEGUI_LIBRARY} - ${TINYXML_LIBRARIES} - ${OpenAL_LIBRARIES} - ${LUA_LIBRARIES} -) +file(GLOB THRIVE_SOUNDS "assets/sounds/*") +file(COPY ${THRIVE_SOUNDS} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Sound/") -target_link_libraries(ThriveLib - ${SWRESAMPLE_LIBRARIES} - ) +file(GLOB THRIVE_VIDEOS "assets/videos/*") +file(COPY ${THRIVE_VIDEOS} DESTINATION "${PROJECT_BINARY_DIR}/bin/Data/Videos/") -# Windows requires using Bullet DEBUG libraries to fix broken build -# But Linux build breaks with those settings -if(WIN32) - - target_link_libraries(ThriveLib - ${BULLET_DYNAMICS_LIBRARY_DEBUG} - ${BULLET_COLLISION_LIBRARY_DEBUG} - ${BULLET_MATH_LIBRARY_DEBUG} - ${BULLET_SOFTBODY_LIBRARY_DEBUG} - ) -else() - target_link_libraries(ThriveLib - ${BULLET_LIBRARIES} - ) +file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/bin/Data/Screenshots") +file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/bin/Data/Cache") -endif() - -target_link_libraries(ThriveLib -${cAudio_LIBRARIES} -) +# ####### +# # Lua # +# ####### +# option(LUA_CHECKS "when ON enables additional Lua safety +# checks. Lowers performance so only use while debugging" +# OFF) -set_target_properties(ThriveLib PROPERTIES - OUTPUT_NAME Thrive -) +# if(LUA_CHECKS) -if(WIN32) - -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist/bin) +# add_definitions(-DSOL_CHECK_ARGUMENTS) + +# endif() -add_executable(Thrive - ${CMAKE_CURRENT_SOURCE_DIR}/src/Main.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/windows/thrive.rc) -else() - add_executable(Thrive - ${CMAKE_CURRENT_SOURCE_DIR}/src/Main.cpp) -endif() -set_target_properties (Thrive PROPERTIES RUNTIME_OUTPUT_DIRECTORY dist/bin) +# include_directories( +# "${CMAKE_CURRENT_SOURCE_DIR}/contrib/lua" +# ) -# Compile executable +# link_directories( +# "${CMAKE_CURRENT_SOURCE_DIR}/contrib/lua/luajit/src" +# ) +# set(LUA_FOUND TRUE) -target_link_libraries(Thrive ThriveLib) +# if(WIN32) +# set(LUA_LIBRARIES lua51.dll) +# else() +# set(LUA_LIBRARIES luajit.a dl) +# endif() -################# -# Compile tests # -################# -# Collect sources from sub directories -get_property(TEST_SOURCE_FILES GLOBAL PROPERTY TEST_SOURCE_FILES) -set_source_files_properties( - ${TEST_SOURCE_FILES} - PROPERTIES COMPILE_FLAGS ${WARNING_FLAGS} -) -add_executable(RunTests ${TEST_SOURCE_FILES}) -target_link_libraries(RunTests ThriveLib gtest_main ${LUA_LIBRARIES}) ################# # Documentation # @@ -355,333 +237,13 @@ if(DOXYGEN_FOUND) ) endif() - -########### -# Install # -########### - -# Executable -install(TARGETS Thrive - RUNTIME DESTINATION bin - LIBRARY DESTINATION bin -) - -# Version file - -install(FILES - "${CMAKE_SOURCE_DIR}/thriveversion.ver" - DESTINATION bin -) - -# OGRE config and media - -install(FILES - "${CMAKE_SOURCE_DIR}/ogre_cfg/resources.cfg" - DESTINATION bin -) - -install(FILES - "${CMAKE_SOURCE_DIR}/ogre_cfg/plugins.cfg" - DESTINATION bin - CONFIGURATIONS Release -) - -install(FILES - "${CMAKE_SOURCE_DIR}/ogre_cfg/plugins_d.cfg" - DESTINATION bin - CONFIGURATIONS Debug - RENAME plugins.cfg -) - -install(DIRECTORY "${ASSET_DIRECTORY}/models" - DESTINATION ./ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.mesh" - PATTERN "*.mesh.xml" - PATTERN "*.skeleton" - PATTERN "*.skeleton.xml" -) - -install(DIRECTORY "${ASSET_DIRECTORY}/materials" - DESTINATION ./ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.jpg" - PATTERN "*.jpeg" - PATTERN "*.material" - PATTERN "*.png" - PATTERN "*.cg" - PATTERN "*.program" - PATTERN "*.ps" - PATTERN "*.vs" -) - -install(DIRECTORY - "${ASSET_DIRECTORY}/fonts" - DESTINATION ./ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.ttf" - PATTERN "*.fontdef" - PATTERN "*.font" -) - -install(DIRECTORY - "${CMAKE_SOURCE_DIR}/scripts" - DESTINATION ./ - CONFIGURATIONS Release Debug -) - -install(DIRECTORY - "${ASSET_DIRECTORY}/gui/imagesets" - DESTINATION ./gui/ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.imageset" - PATTERN "*.jpg" - PATTERN "*.png" -) - -install(DIRECTORY - "${ASSET_DIRECTORY}/gui/animations" - DESTINATION ./gui/ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.anims" -) - -install(DIRECTORY - "${ASSET_DIRECTORY}/gui/layouts" - DESTINATION ./gui/ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.layout" - PATTERN "*.wnd" -) -install(DIRECTORY - "${ASSET_DIRECTORY}/gui/looknfeel" - DESTINATION ./gui/ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.looknfeel" -) -install(DIRECTORY - "${ASSET_DIRECTORY}/gui/schemes" - DESTINATION ./gui/ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.scheme" -) - -install(DIRECTORY - "${ASSET_DIRECTORY}/sounds" - DESTINATION ./ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.ogg" - PATTERN "*.wav" -) - -install(DIRECTORY - "${ASSET_DIRECTORY}/videos" - DESTINATION ./ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.wmv" - PATTERN "*.avi" - PATTERN "*.mp4" -) - -install(DIRECTORY - "${ASSET_DIRECTORY}/definitions" - DESTINATION ./ - CONFIGURATIONS Release Debug - FILES_MATCHING - PATTERN "*.xml" -) - -# Install Runtime Libraries -if(WIN32) - - if (SYSTEM_DLLS) - INSTALL(FILES - ${SYSTEM_DLLS} - DESTINATION bin - ) - endif() - - INSTALL(FILES - ${Boost_LIBRARIES} - DESTINATION bin - ) - -# INSTALL(FILES -# ${IRRKLANG_LIBRARIES_DLL} -# DESTINATION bin -# ) - - foreach(OGRE_PLUGIN ${OGRE_PLUGINS}) - # Release - install(FILES - "${OGRE_PLUGIN_DIR_REL}/${OGRE_PLUGIN}.dll" - DESTINATION bin - CONFIGURATIONS Release - ) - # Debug - install(FILES - "${OGRE_PLUGIN_DIR_DBG}/${OGRE_PLUGIN}_d.dll" - DESTINATION bin - CONFIGURATIONS Debug - ) - endforeach() - - install(FILES - "${OGRE_PLUGIN_DIR_REL}/OgreMain.dll" - "${OGRE_PLUGIN_DIR_REL}/RenderSystem_GL.dll" - "${OGRE_PLUGIN_DIR_REL}/OIS.dll" - "${MINGW_ENV}/install/bin/Release/cg.dll" - DESTINATION bin - CONFIGURATIONS Release - ) - - install(FILES - "${OGRE_PLUGIN_DIR_DBG}/OgreMain_d.dll" - "${OGRE_PLUGIN_DIR_DBG}/RenderSystem_GL_d.dll" - "${OGRE_PLUGIN_DIR_DBG}/OIS_d.dll" - "${MINGW_ENV}/install/bin/Debug/cg.dll" - DESTINATION bin - CONFIGURATIONS Debug - ) - - - - - - install(FILES - "${MINGW_ENV}/install/bin/libCEGUIBase-${FIND_CEGUI_VERSION}_d.dll" - "${MINGW_ENV}/install/bin/libCEGUIOgreRenderer-${FIND_CEGUI_VERSION}_d.dll" - "${MINGW_ENV}/install/bin/libCEGUITinyXMLParser_d.dll" - "${MINGW_ENV}/install/bin/libCEGUICoreWindowRendererSet_d.dll" - "${MINGW_ENV}/install/bin/Debug/libfreetype_d.dll" - "${MINGW_ENV}/install/bin/Debug/libjpeg_d.dll" - "${MINGW_ENV}/install/bin/Debug/libSILLY_d.dll" - "${MINGW_ENV}/install/bin/Debug/libzlib_d.dll" - "${MINGW_ENV}/bin/libgcc_s_dw2-1.dll" - "${MINGW_ENV}/install/bin/libcAudio_d.dll" - "${MINGW_ENV}/install/bin/libcAudio.dll" - "${MINGW_ENV}/install/bin/wrap_oal.dll" - "${MINGW_ENV}/install/bin/OpenAL32.dll" - "${MINGW_ENV}/install/bin/avcodec-57.dll" - "${MINGW_ENV}/install/bin/avformat-57.dll" - "${MINGW_ENV}/install/bin/avutil-55.dll" - "${MINGW_ENV}/install/bin/swscale-4.dll" - "${MINGW_ENV}/install/bin/swresample-2.dll" - "${CMAKE_SOURCE_DIR}/mingw_setup/lua51.dll" - "${CMAKE_SOURCE_DIR}/mingw_setup/luajit.exe" - DESTINATION bin - CONFIGURATIONS Debug - ) - - install(FILES - "${MINGW_ENV}/install/bin/libCEGUIBase-${FIND_CEGUI_VERSION}.dll" - "${MINGW_ENV}/install/bin/libCEGUIOgreRenderer-${FIND_CEGUI_VERSION}.dll" - "${MINGW_ENV}/install/bin/libCEGUITinyXMLParser.dll" - "${MINGW_ENV}/install/bin/libCEGUICoreWindowRendererSet.dll" - "${MINGW_ENV}/install/bin/Release/libfreetype.dll" - "${MINGW_ENV}/install/bin/Release/libjpeg.dll" - "${MINGW_ENV}/install/bin/Release/liblibpng.dll" - "${MINGW_ENV}/install/bin/Release/libSILLY.dll" - "${MINGW_ENV}/install/bin/Release/libzlib.dll" - "${MINGW_ENV}/install/bin/Release/libzlib.dll" - "${MINGW_ENV}/bin/libgcc_s_dw2-1.dll" - "${MINGW_ENV}/install/bin/libcAudio.dll" - "${MINGW_ENV}/install/bin/wrap_oal.dll" - "${MINGW_ENV}/install/bin/OpenAL32.dll" - "${MINGW_ENV}/install/bin/avcodec-57.dll" - "${MINGW_ENV}/install/bin/avformat-57.dll" - "${MINGW_ENV}/install/bin/avutil-55.dll" - "${MINGW_ENV}/install/bin/swscale-4.dll" - "${MINGW_ENV}/install/bin/swresample-2.dll" - DESTINATION bin - CONFIGURATIONS Release - ) - - install(FILES - "${ASSET_DIRECTORY}/misc/Thrive.exe" - DESTINATION ./ - ) - -elseif(UNIX) - - SeparateLibrariesByBuildType( - "${OGRE_LIBRARIES}" - OGRE_MAIN_DBG - OGRE_MAIN_REL - ) - InstallFollowingSymlink( - ${OGRE_MAIN_REL} - bin - Release - False - ) - InstallFollowingSymlink( - ${OGRE_MAIN_DBG} - bin - Debug - False - ) - - foreach(OGRE_PLUGIN ${OGRE_PLUGINS}) - SeparateLibrariesByBuildType( - "${OGRE_${OGRE_PLUGIN}_LIBRARIES}" - OGRE_PLUGIN_LIB_DBG - OGRE_PLUGIN_LIB_REL - ) - - if(NOT EXISTS "${OGRE_PLUGIN_LIB_REL}" OR NOT EXISTS "${OGRE_PLUGIN_LIB_DBG}") - message(SEND_ERROR "Ogre plugin file doesn't exist: ${OGRE_PLUGIN} . Did you build " - "all the required Ogre plugins?") - endif() - - # Release - InstallFollowingSymlink( - ${OGRE_PLUGIN_LIB_REL} - bin - Release - True - ) - # Debug - InstallFollowingSymlink( - ${OGRE_PLUGIN_LIB_DBG} - bin - Debug - True - ) - endforeach() - -endif() - -############################################################################### -# CPack -############################################################################### - -configure_file("${CMAKE_SOURCE_DIR}/cpack/zip.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cpack/zip.cmake" @ONLY -) - -add_custom_target(zip - COMMAND cpack --config "${CMAKE_CURRENT_BINARY_DIR}/cpack/zip.cmake" - DEPENDS Thrive -) - ############################################################################### # Linux package ############################################################################### if(UNIX) + # TODO: fix this, also add windows support - file(READ "thriveversion.ver" THRIVE_VERSION) set(LINUX_LIBRARIES "${cAudio_LIBRARIES}" "${BULLET_LIBRARIES}" "${SWRESAMPLE_LIBRARIES}" "${OgreFFMPEG_LIBRARIES}" "${FFMPEG_LIBRARIES}" "${Boost_LIBRARIES}" "${OGRE_LIBRARIES}" "${OIS_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}" diff --git a/LICENSE.txt b/LICENSE.txt index 8bd1010f330..454c985b3de 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,5 @@ Thrive Game -Copyright (C) 2013 Revolutionary Games +Copyright (C) 2013-2018 Revolutionary Games Thrive is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/QuickRecompile.rb b/QuickRecompile.rb new file mode 100755 index 00000000000..a8ba9733123 --- /dev/null +++ b/QuickRecompile.rb @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby +# This script runs the setup with options that make recompiling much faster (but it doesn't +# update everything!) +require_relative 'RubySetupSystem/RubyCommon.rb' + +system("ruby SetupThrive.rb --no-packagemanager --no-subproject-deps") +exit $?.exitstatus == 0 diff --git a/README.md b/README.md index 0d4d8276383..81f885e8fee 100644 --- a/README.md +++ b/README.md @@ -6,45 +6,31 @@ This is the code repository for Thrive. For more information, visit Overview ---------------- - Repository structure: -- assets: An SVN repository that doesn't follow with the git repository. This contains all the assets such as models and other binaries. Get it with SVN Checkout http://assets.revolutionarygamesstudio.com -- cmake_modules: Scripts used by cmake when building the project binaries to find the dependencies. The dependencies will, for windows users, be installed with the mingw_setup directory. -- contrib: Git submodules and other external code bases we use for the project. -- cpack: Script used by 7zip. -- doc: Documentation files. Contains style guide, engine overview and other useful documentation. . -- mingw_setup: Dependency installation for windows and linux->windows cross-compiling (cross-compiling currently deprecated). You will need to run this to build the project files. -- ogre_cfg: Ogre configuration files for resources and plugins. This is installed with distributions. -- scripts: Lua scripts that contain part of the codebase. Lua scripts are used for easier development and code here can then later be transferred to the C++ base for performance. We use luabind for binding. -- src: The C++ code base containing the engine and other sections. - -Remember to get the luabind and google test submodules with git submodule update --init --recursive. +- assets: An SVN repository that doesn't follow with the git repository. This contains all the assets such as models and other binaries. It is located at [asset repository][asset_repository] but it will be automatically downloaded by the setup script. +- doc: Documentation files. Contains style guide, engine overview and other useful documentation. +- scripts: AngelScript scripts that contain part of the codebase. Scripts are used for easier development and code here can then later be transferred to the C++ base for performance. +- src: The C++ code base containing the common helper classes and gameplay code moved to C++. +- test: Contains tests that will ensure that core parts work correctly. These are currently really lacking. Getting Involved ---------------- Depending on what you want to contribute, you need to take different steps to get your development environment set up. +There are also other useful documents in the doc folder not mentioned here. + ### Script Authors -If you only want to modify the Lua scripts, you can obtain a +If you only want to modify the AngelScript scripts, you can obtain a working copy of the game from official releases here: http://revolutionarygamesstudio.com/releases/ alternatively you can request a newer version from developers or compile the project yourself. Be sure to have a look at the [styleguide][styleguide], -both for guidelines on code formatting and git usage. - -### C++ Programmers -To compile Thrive yourself, you will not only need to clone this git -repository, but also the Subversion [asset repository][asset_repository], -username and password both "anonymous". The best place to put the assets -is in your code repository's `assets` subdirectory. If, for whatever -reason, you want to check it out to another place, you will have to modify -the `ASSET_DIRECTORY` variable in the CMake setup. Offloading art assets -into Subversion was necessary due to size constraints for GitHub repositories. - -Windows developers should follow the procedure outlined in the [mingw setup guide][mingwsetupguide]. +both for guidelines on code formatting and git usage. +And [AngelScript primer][asprimer] for scripting help. -Linux developers should follow the instructions in [linux setup guide][linuxsetupguide] +### C++ Programmers +To compile Thrive yourself, you will not only need to follow the [setup instructions][setupguide]. Be sure to have a look at the [styleguide][styleguide], both for guidelines on code formatting and git usage. @@ -55,13 +41,10 @@ You can find official releases here: http://revolutionarygamesstudio.com/release alternatively you can request a newer version from developers, or compile the project yourself. After you have obtained a working version of the game, you can place any new assets in the corresponding subdirectories: -sound, models, materials and gui and the game will automatically detect up your new files, which you can then use in scripts. -An example of modifying a script to use your model would be to open scripts/microbe_stage/setup.lua with a text editor and -find the setupEmitter function and edit the line that says: - sceneNode.meshName = "molecule.mesh" -to - sceneNode.meshName = "myNewModel.mesh" -Similarly you can find sections of the scripts that use other assets and replace the assets they use. (often in setup scripts) +bin/Data/Sound, bin/Data/Models, bin/Data/Materials and gui and the game will automatically detect up your new files, which you can then use in scripts. +An example of modifying a script to use your model would be to open scripts/microbe_stage/organelle_table.as with a text editor and +find 'nucleusParameters.mesh = "nucleus.mesh";' that sets the model used by the nucleus and change that to your new model file. +Similarly you can find sections of the scripts that use other assets and replace the assets they use. If you are truly uncomfortable with editing scripts you can simply try stealing the names of existing assets. For example going into the sound subdirectory and stealing the name "microbe-theme-1.ogg" by renaming your new sound-file to that and the game will then play that sound instead. @@ -76,10 +59,9 @@ model to be used in Thrive it will need to be converted. You can contact a devel A good tutorial for converting blender files can be found [here][blender_ogre_tutorial] Note that you should make sure to use a version of blender that has a corresponding version of blender2ogre to do the conversion. -[blender_ogre_tutorial]: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=79616&p=504590 "Blender to ogre tutorial" -[asset_repository]: http://assets.revolutionarygamesstudio.com/ "Asset Repository" +[blender_ogre_tutorial]: http://thrivegame.wikidot.com/blender-and-ogre-tutorial "Blender to ogre tutorial" +[asset_repository]: https://boostslair.com/svn/thrive_assets "Asset Repository" [tortoiseSVN]: http://tortoisesvn.net/docs/release/TortoiseSVN_en/ "Tortoise SVN" -[mingw]: http://www.github.com/Revolutionary-Games/Thrive/blob/master/mingw_setup/readme.txt "MinGW setup guide" -[styleguide]: http://www.github.com/Revolutionary-Games/Thrive/blob/master/doc/style_guide.dox "Styleguide" -[mingwsetupguide]: http://www.github.com/Revolutionary-Games/Thrive/blob/master/mingw_setup/readme.txt "mingw setup guide" -[linuxsetupguide]: https://github.com/Revolutionary-Games/Thrive/blob/master/linux_setup/readme.md "linux setup guide" +[styleguide]: doc/style_guide.md "Styleguide" +[setupguide]: doc/setup_instructions.md +[asprimer]: doc/angelscript_primer.md "AngelScript primer" diff --git a/RubySetupSystem b/RubySetupSystem new file mode 160000 index 00000000000..6126dead89f --- /dev/null +++ b/RubySetupSystem @@ -0,0 +1 @@ +Subproject commit 6126dead89f636053e1d881f16bbd42cafc50d9b diff --git a/SetupThrive.rb b/SetupThrive.rb index 7c3f68261d9..03967bea8cd 100755 --- a/SetupThrive.rb +++ b/SetupThrive.rb @@ -1,168 +1,119 @@ #!/usr/bin/env ruby # coding: utf-8 -# Setup script for Thrive. Windows mode is experimental and isn't tested +# Setup script for Thrive. + +# RubySetupSystem Bootstrap +if not File.exists? "RubySetupSystem/RubySetupSystem.rb" + puts "Initializing RubySetupSystem" + system "git submodule init && git submodule update --recursive" + + if $?.exitstatus != 0 + abort("Failed to initialize or update git submodules. " + + "Please make sure git is in path and " + + "you have an ssh key setup for your github account") + end +else + # Make sure RubySetupSystem is up to date + # This may make debugging RubySetupSystem harder so feel free to comment out + system "git submodule update" +end require 'fileutils' -require_relative 'linux_setup/RubyCommon.rb' -def checkRunFolder(suggestedfolder) +require_relative 'RubySetupSystem/RubyCommon.rb' - if File.exist? "thriveversion.ver" or File.basename(Dir.getwd) == "thrive" +def checkRunFolder(suggested) - # Inside thrive folder - info "Running from inside thrive folder" + versionFile = File.join(suggested, "thriveversion.ver") - return File.expand_path("..", Dir.pwd) - - else + onError("Not ran from Thrive base directory!") if not File.exist?("SetupThrive.rb") - # Outside, install thrive here - info "Running outside thrive folder. Thrive folder will be created here" + thirdPartyFolder = File.join suggested, "ThirdParty" - return Dir.pwd - - end + FileUtils.mkdir_p thirdPartyFolder + FileUtils.mkdir_p File.join suggested, "build", "ThirdParty" + + thirdPartyFolder + end def projectFolder(baseDir) - return File.join baseDir, "thrive" + File.expand_path File.join(baseDir, "../") end -ThriveBranch = "master" -#ThriveBranch = "ruby_setup" -SkipPackageManager = false - -require_relative 'linux_setup/RubySetupSystem.rb' - -# Install packages -if BuildPlatform == "linux" and not SkipPackageManager - - LinuxOS = getLinuxOS +def parseExtraArgs - info "Installing packages" + if ARGV.length > 1 - CommonPackages = "cmake make git mercurial svn" - - if LinuxOS.casecmp("Fedora") == 0 - - PackageManager = "dnf install -y " + onError("Unrecognized command line options.\n" + + "Expected only username in addition to other arguments. Got: #{ARGV.join(' ')}") - PackagesToInstall = "bullet-devel boost gcc-c++ libXaw-devel freetype-devel " + - "freeimage-devel zziplib-devel boost-devel ois-devel tinyxml-devel " + - "glm-devel ffmpeg-devel ffmpeg-libs openal-soft-devel libatomic" - - elsif LinuxOS.casecmp("Ubuntu") == 0 + end + + $svnUser = ARGV[0] + ARGV.shift + +end - PackageManager = "apt-get install -y " - - PackagesToInstall = "bullet-dev boost-dev build-essential automake libtool " + - "libfreetype6-dev libfreeimage-dev libzzip-dev libxrandr-dev " + - "libxaw7-dev freeglut3-dev libgl1-mesa-dev libglu1-mesa-dev " + - "libois-dev libboost-thread-dev tinyxml-dev glm-dev ffmpeg-dev " + - "libavutil-dev libopenal-dev" +require_relative 'RubySetupSystem/RubySetupSystem.rb' +require_relative 'RubySetupSystem/Libraries/SetupLeviathan.rb' - elsif LinuxOS.casecmp("Arch") == 0 +if !$svnUser + $svnUser = "thrive" +end - PackageManager = "pacman -S --noconfirm --color auto --needed" - - PackagesToInstall = "bullet boost automake libtool freetype2 freeimage zziplib " + - "libxrandr libxaw freeglut libgl ois tinyxml glm ffmpeg openal" - - if `pacman -Qs gcc-multilib` - - PackagesToInstall += " gcc-multilib autoconf automake binutils bison fakeroot file " + - "findutils flex gawk gettext grep groff gzip libtool m4 make " + - "pacman patch pkg-config sed sudo texinfo util-linux which" - else - - PackagesToInstall += " base-devel" - - end - - else +WantedURL = "https://#{$svnUser}@boostslair.com/svn/thrive_assets" - onError "Unknown operating system: #{LinuxOS}" - - end +leviathan = Leviathan.new( + version: "develop", + # Doesn't actually work, but leviathan doesn't install with sudo by + # default, or install at all for that matter + noInstallSudo: true +) - info "Installing prerequisite libraries, be prepared to type password for sudo" +puts "" +puts "" - system "sudo #{PackageManager} #{CommonPackages} #{PackagesToInstall}" - onError "Failed to install package manager dependencies" if $?.exitstatus > 0 - - success "Packages installed" - -end +info "Running the engine compilation" -installer = Installer.new( - Array[CAudio.new, Ogre.new, - # CEGUI uses commit 869014de5669 - CEGUI.new - ]) +installer = Installer.new([leviathan]) installer.run info "Thrive folder setup" +if not File.exist? ProjectDir + onError "'thrive' folder is missing" -if not File.exist? File.join(CurrentDir, "thrive") - - info "Thrive folder doesn't exist, cloning from git" - - Dir.chdir(CurrentDir) do - - system "git clone https://github.com/Revolutionary-Games/Thrive.git thrive" - onError "Failed to clone repository" if $?.exitstatus > 0 - - Dir.chdir("thrive") do - - systemChecked "git submodule update --init --recursive" - - end - end end success "Thrive folder exists" -Dir.chdir(File.join(CurrentDir, "thrive")) do +Dir.chdir(ProjectDir) do - system "git checkout #{ThriveBranch}" + system "git pull" if $?.exitstatus > 0 - warning "Failed to checkout target thrive branch" - - else - - systemChecked "git pull --recurse-submodules origin #{ThriveBranch}" + warning "Failed to pull thrive repo" end - systemChecked "git submodule update --recursive" - - # submodule init check - if not File.exists? File.join(CurrentDir, "thrive", "contrib/lua/luajit/src", "lua.hpp") - - warning "Submodules haven't been initialized, initializing now" - - systemChecked "git submodule update --init --recursive" - - success "Submodules are now initialized" - - end + runOpen3Checked("git", "submodule", "update", "--recursive") info "Checking assets" if not File.exist? "assets" info "Getting assets" - - system "svn checkout http://assets.revolutionarygamesstudio.com/ assets" - onError "Failed to get thrive assets repository" if $?.exitstatus > 0 + system(["svn", "checkout", "--username", $svnUser, WantedURL, "assets"].join(' ')) + if $?.exitstatus != 0 + onError "Failed to get thrive assets repository" + end else @@ -170,6 +121,8 @@ def projectFolder(baseDir) Dir.chdir("assets") do + verifySVNUrl(WantedURL) + system "svn up" onError "Failed to update thrive assets" if $?.exitstatus > 0 @@ -179,53 +132,51 @@ def projectFolder(baseDir) success "Assets are good to go" - info "Building luajit" + # info "Building luajit" - Dir.chdir(File.join(CurrentDir, "thrive", "contrib/lua/luajit/src")) do + # Dir.chdir(File.join(ProjectDir, "contrib/lua/luajit/src")) do - # Make sure XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT is uncommented - outdata = File.read("Makefile").gsub(/#XCFLAGS\+= -DLUAJIT_ENABLE_LUA52COMPAT/, - "XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT") + # # Make sure XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT is uncommented + # outdata = File.read("Makefile").gsub(/#XCFLAGS\+= -DLUAJIT_ENABLE_LUA52COMPAT/, + # "XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT") - File.open("Makefile", 'w') do |out| - out << outdata - end + # File.open("Makefile", 'w') do |out| + # out << outdata + # end - runCompiler CompileThreads + # runCompiler $compileThreads - onError "Failed to compile luajit" if $?.exitstatus > 0 + # onError "Failed to compile luajit" if $?.exitstatus > 0 - end + # end - success "luajit is ok" + # success "luajit is ok" FileUtils.mkdir_p "build" - FileUtils.mkdir_p "build/dist" - FileUtils.mkdir_p "build/dist/bin" - - info "Making links" - - # It seems that if the link is created when it already exists a link is created into - # the target folder for some reason - createLinkIfDoesntExist "assets/cegui_examples", "cegui_examples" - createLinkIfDoesntExist "assets/fonts", "fonts" - createLinkIfDoesntExist "assets/gui", "gui" - createLinkIfDoesntExist "assets/materials", "materials" - createLinkIfDoesntExist "assets/models", "models" - createLinkIfDoesntExist "assets/sounds", "sounds" - createLinkIfDoesntExist "assets/videos", "videos" - - Dir.chdir("build") do - FileUtils.ln_sf "dist/bin/Thrive", "Thrive" - end - info "Copying Ogre resources file" - FileUtils.cp "ogre_cfg/resources.cfg", "./build/resources.cfg" +end - info "Copying completety pointless Ogre files" +# Symlink the textures and fonts from assets to make local previewing of the GUI easier +if OS.windows? + # These need to run in cmd as admin, for some reason + info "Creating junctions for assets to be referenced from gui " + + "html without running cmake every time" + runSystemSafe "cmd", "/c", "mklink", "/J", + convertPathToWindows(File.join(ProjectDir, "Textures")), + convertPathToWindows(File.join(ProjectDir, "assets", "textures")) + runSystemSafe "cmd", "/c", "mklink", "/J", + convertPathToWindows(File.join(ProjectDir, "Fonts")), + convertPathToWindows(File.join(ProjectDir, "assets", "fonts")) +else + if !File.exists? File.join(ProjectDir, "Textures") + FileUtils.ln_sf File.join(ProjectDir, "assets", "textures"), + File.join(ProjectDir, "Textures") + end - FileUtils.cp "/usr/local/share/OGRE/plugins.cfg", "./build/plugins.cfg" - + if !File.exists? File.join(ProjectDir, "Fonts") + FileUtils.ln_sf File.join(ProjectDir, "assets", "fonts"), + File.join(ProjectDir, "Fonts") + end end success "Thrive folder and assets are good to go" @@ -236,23 +187,30 @@ def projectFolder(baseDir) # Build directory is made earlier -Dir.chdir(File.join(CurrentDir, "thrive", "build")) do - - runCMakeConfigure "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" +Dir.chdir(File.join(ProjectDir, "build")) do - if $?.exitstatus > 0 + if !runCMakeConfigure [] onError "Failed to configure Thrive. Are you using a broken version, " + "or did a dependency fail to install?" end - runCompiler CompileThreads - onError "Failed to compile Thrive " if $?.exitstatus > 0 + if !TC.runCompiler + onError "Failed to compile Thrive" + end end success "Done compiling thrive" -info "run the game with '#{CurrentDir}/thrive/build/Thrive'" +if OS.windows? + info "Open build/Thrive.sln and start coding" +else + info "run the game with '#{CurrentDir}/thrive/build/Thrive'" +end + +puts "" +info "NOTE: when changing the scripts or assets you must rerun cmake to make it move the " + + "changed files to the build folder" success "Done" diff --git a/cmake_modules/FindBoost.cmake b/cmake_modules/FindBoost.cmake deleted file mode 100644 index 17aba1b2219..00000000000 --- a/cmake_modules/FindBoost.cmake +++ /dev/null @@ -1,1212 +0,0 @@ -# - Try to find Boost include dirs and libraries -# Usage of this module as follows: -# -# NOTE: Take note of the Boost_ADDITIONAL_VERSIONS variable below. -# Due to Boost naming conventions and limitations in CMake this find -# module is NOT future safe with respect to Boost version numbers, -# and may break. -# -# == Using Header-Only libraries from within Boost: == -# -# find_package( Boost 1.36.0 ) -# if(Boost_FOUND) -# include_directories(${Boost_INCLUDE_DIRS}) -# add_executable(foo foo.cc) -# endif() -# -# -# == Using actual libraries from within Boost: == -# -# set(Boost_USE_STATIC_LIBS ON) -# set(Boost_USE_MULTITHREADED ON) -# set(Boost_USE_STATIC_RUNTIME OFF) -# find_package( Boost 1.36.0 COMPONENTS date_time filesystem system ... ) -# -# if(Boost_FOUND) -# include_directories(${Boost_INCLUDE_DIRS}) -# add_executable(foo foo.cc) -# target_link_libraries(foo ${Boost_LIBRARIES}) -# endif() -# -# -# The components list needs to contain actual names of boost libraries only, -# such as "date_time" for "libboost_date_time". If you're using parts of -# Boost that contain header files only (e.g. foreach) you do not need to -# specify COMPONENTS. -# -# You should provide a minimum version number that should be used. If you provide this -# version number and specify the REQUIRED attribute, this module will fail if it -# can't find the specified or a later version. If you specify a version number this is -# automatically put into the considered list of version numbers and thus doesn't need -# to be specified in the Boost_ADDITIONAL_VERSIONS variable (see below). -# -# NOTE for Visual Studio Users: -# Automatic linking is used on MSVC & Borland compilers by default when -# #including things in Boost. It's important to note that setting -# Boost_USE_STATIC_LIBS to OFF is NOT enough to get you dynamic linking, -# should you need this feature. Automatic linking typically uses static -# libraries with a few exceptions (Boost.Python is one). -# -# Please see the section below near Boost_LIB_DIAGNOSTIC_DEFINITIONS for -# more details. Adding a target_link_libraries() as shown in the example -# above appears to cause VS to link dynamically if Boost_USE_STATIC_LIBS -# gets set to OFF. It is suggested you avoid automatic linking since it -# will make your application less portable. -# -# =========== The mess that is Boost_ADDITIONAL_VERSIONS (sorry?) ============ -# -# OK, so the Boost_ADDITIONAL_VERSIONS variable can be used to specify a list of -# boost version numbers that should be taken into account when searching -# for Boost. Unfortunately boost puts the version number into the -# actual filename for the libraries, so this variable will certainly be needed -# in the future when new Boost versions are released. -# -# Currently this module searches for the following version numbers: -# 1.33, 1.33.0, 1.33.1, 1.34, 1.34.0, 1.34.1, 1.35, 1.35.0, 1.35.1, -# 1.36, 1.36.0, 1.36.1, 1.37, 1.37.0, 1.38, 1.38.0, 1.39, 1.39.0, -# 1.40, 1.40.0, 1.41, 1.41.0, 1.42, 1.42.0, 1.43, 1.43.0, 1.44, 1.44.0, -# 1.45, 1.45.0, 1.46, 1.46.0, 1.46.1, 1.47, 1.47.0, 1.48, 1.48.0, -# 1.49, 1.49.0, 1.50, 1.50.0, 1.51, 1.51.0, 1.52, 1.52.0, -# 1.53, 1.53.0, 1.54, 1.54.0, 1.55, 1.55.0, 1.56, 1.56.0 -# -# NOTE: If you add a new major 1.x version in Boost_ADDITIONAL_VERSIONS you should -# add both 1.x and 1.x.0 as shown above. Official Boost include directories -# omit the 3rd version number from include paths if it is 0 although not all -# binary Boost releases do so. -# -# set(Boost_ADDITIONAL_VERSIONS "1.78" "1.78.0" "1.79" "1.79.0") -# -# ===================================== ============= ======================== -# -# Variables used by this module, they can change the default behaviour and -# need to be set before calling find_package: -# -# Boost_USE_MULTITHREADED Can be set to OFF to use the non-multithreaded -# boost libraries. If not specified, defaults -# to ON. -# -# Boost_USE_STATIC_LIBS Can be set to ON to force the use of the static -# boost libraries. Defaults to OFF. -# -# Boost_NO_SYSTEM_PATHS Set to TRUE to suppress searching in system -# paths (or other locations outside of BOOST_ROOT -# or BOOST_INCLUDEDIR). Useful when specifying -# BOOST_ROOT. Defaults to OFF. -# [Since CMake 2.8.3] -# -# Boost_NO_BOOST_CMAKE Do not do a find_package call in config mode -# before searching for a regular boost install. -# This will avoid finding boost-cmake installs. -# Defaults to OFF. -# [Since CMake 2.8.6] -# -# Boost_USE_STATIC_RUNTIME If enabled, searches for boost libraries -# linked against a static C++ standard library -# ('s' ABI tag). This option should be set to -# ON or OFF because the default behavior -# if not specified is platform dependent -# for backwards compatibility. -# [Since CMake 2.8.3] -# -# Boost_USE_DEBUG_PYTHON If enabled, searches for boost libraries -# compiled against a special debug build of -# Python ('y' ABI tag). Defaults to OFF. -# [Since CMake 2.8.3] -# -# Boost_USE_STLPORT If enabled, searches for boost libraries -# compiled against the STLPort standard -# library ('p' ABI tag). Defaults to OFF. -# [Since CMake 2.8.3] -# -# Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS -# If enabled, searches for boost libraries -# compiled against the deprecated STLPort -# "native iostreams" feature ('n' ABI tag). -# Defaults to OFF. -# [Since CMake 2.8.3] -# -# Other Variables used by this module which you may want to set. -# -# Boost_ADDITIONAL_VERSIONS A list of version numbers to use for searching -# the boost include directory. Please see -# the documentation above regarding this -# annoying, but necessary variable :( -# -# Boost_DEBUG Set this to TRUE to enable debugging output -# of FindBoost.cmake if you are having problems. -# Please enable this before filing any bug -# reports. -# -# Boost_DETAILED_FAILURE_MSG FindBoost doesn't output detailed information -# about why it failed or how to fix the problem -# unless this is set to TRUE or the REQUIRED -# keyword is specified in find_package(). -# [Since CMake 2.8.0] -# -# Boost_COMPILER Set this to the compiler suffix used by Boost -# (e.g. "-gcc43") if FindBoost has problems finding -# the proper Boost installation -# -# Boost_THREADAPI When building boost.thread, sometimes the name of the -# library contains an additional "pthread" or "win32" -# string known as the threadapi. This can happen when -# compiling against pthreads on Windows or win32 threads -# on Cygwin. You may specify this variable and if set -# when FindBoost searches for the Boost threading library -# it will first try to match the threadapi you specify. -# For Example: libboost_thread_win32-mgw45-mt-1_43.a -# might be found if you specified "win32" here before -# falling back on libboost_thread-mgw45-mt-1_43.a. -# [Since CMake 2.8.3] -# -# Boost_REALPATH Resolves symbolic links for discovered boost libraries -# to assist with packaging. For example, instead of -# Boost_SYSTEM_LIBRARY_RELEASE being resolved to -# "/usr/lib/libboost_system.so" it would be -# "/usr/lib/libboost_system.so.1.42.0" instead. -# This does not affect linking and should not be -# enabled unless the user needs this information. -# [Since CMake 2.8.3] -# - - -# -# These last three variables are available also as environment variables: -# Also, note they are completely UPPERCASE, except Boost_DIR. -# -# Boost_DIR or The preferred installation prefix for searching for -# BOOST_ROOT or BOOSTROOT Boost. Set this if the module has problems finding -# the proper Boost installation. -# -# Note that Boost_DIR behaves exactly as _DIR -# variables are documented to behave in find_package's -# Config mode. That is, if it is set as a -D argument -# to CMake, it must point to the location of the -# BoostConfig.cmake or Boost-config.cmake file. If it -# is set as an environment variable, it must point to -# the root of the boost installation. BOOST_ROOT and -# BOOSTROOT, on the other hand, will point to the root -# in either case. -# -# To prevent falling back on the system paths, set -# Boost_NO_SYSTEM_PATHS to true. -# -# To avoid finding boost-cmake installations, set -# Boost_NO_BOOST_CMAKE to true. -# -# BOOST_INCLUDEDIR Set this to the include directory of Boost, if the -# module has problems finding the proper Boost installation -# -# BOOST_LIBRARYDIR Set this to the lib directory of Boost, if the -# module has problems finding the proper Boost installation -# -# Variables defined by this module: -# -# Boost_FOUND System has Boost, this means the include dir was -# found, as well as all the libraries specified in -# the COMPONENTS list. -# -# Boost_INCLUDE_DIRS Boost include directories: not cached -# -# Boost_INCLUDE_DIR This is almost the same as above, but this one is -# cached and may be modified by advanced users -# -# Boost_LIBRARIES Link to these to use the Boost libraries that you -# specified: not cached -# -# Boost_LIBRARY_DIRS The path to where the Boost library files are. -# -# Boost_VERSION The version number of the boost libraries that -# have been found, same as in version.hpp from Boost -# -# Boost_LIB_VERSION The version number in filename form as -# it's appended to the library filenames -# -# Boost_MAJOR_VERSION major version number of boost -# Boost_MINOR_VERSION minor version number of boost -# Boost_SUBMINOR_VERSION subminor version number of boost -# -# Boost_LIB_DIAGNOSTIC_DEFINITIONS [WIN32 Only] You can call -# add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) -# to have diagnostic information about Boost's -# automatic linking outputted during compilation time. -# -# For each component you specify in find_package(), the following (UPPER-CASE) -# variables are set. You can use these variables if you would like to pick and -# choose components for your targets instead of just using Boost_LIBRARIES. -# -# Boost_${COMPONENT}_FOUND True IF the Boost library "component" was found. -# -# Boost_${COMPONENT}_LIBRARY Contains the libraries for the specified Boost -# "component" (includes debug and optimized keywords -# when needed). - -#============================================================================= -# Copyright 2006-2009 Kitware, Inc. -# Copyright 2006-2008 Andreas Schneider -# Copyright 2007 Wengo -# Copyright 2007 Mike Jackson -# Copyright 2008 Andreas Pakulat -# Copyright 2008-2012 Philip Lowman -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - - -#------------------------------------------------------------------------------- -# Before we go searching, check whether boost-cmake is avaialble, unless the -# user specifically asked NOT to search for boost-cmake. -# -# If Boost_DIR is set, this behaves as any find_package call would. If not, -# it looks at BOOST_ROOT and BOOSTROOT to find Boost. -# -if (NOT Boost_NO_BOOST_CMAKE) - # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, - # since these are more conventional for Boost. - if ("$ENV{Boost_DIR}" STREQUAL "") - if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") - set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) - elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") - set(ENV{Boost_DIR} $ENV{BOOSTROOT}) - endif() - endif() - - # Do the same find_package call but look specifically for the CMake version. - # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no - # need to delegate them to this find_package call. - find_package(Boost QUIET NO_MODULE) - - # If we found boost-cmake, then we're done. Print out what we found. - # Otherwise let the rest of the module try to find it. - if (Boost_FOUND) - message("Boost ${Boost_FIND_VERSION} found.") - if (Boost_FIND_COMPONENTS) - message("Found Boost components:") - message(" ${Boost_FIND_COMPONENTS}") - endif() - return() - endif() -endif() - - -#------------------------------------------------------------------------------- -# FindBoost functions & macros -# - -############################################ -# -# Check the existence of the libraries. -# -############################################ -# This macro was taken directly from the FindQt4.cmake file that is included -# with the CMake distribution. This is NOT my work. All work was done by the -# original authors of the FindQt4.cmake file. Only minor modifications were -# made to remove references to Qt and make this file more generally applicable -# And ELSE/ENDIF pairs were removed for readability. -######################################################################### - -macro(_Boost_ADJUST_LIB_VARS basename) - if(Boost_INCLUDE_DIR ) - if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) - # if the generator supports configuration types then set - # optimized and debug libraries, or if the CMAKE_BUILD_TYPE has a value - if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) - set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - else() - # if there are no configuration types and CMAKE_BUILD_TYPE has no value - # then just use the release libraries - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) - endif() - # FIXME: This probably should be set for both cases - set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) - endif() - - # if only the release version was found, set the debug variable also to the release version - if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) - set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) - endif() - - # if only the debug version was found, set the release variable also to the debug version - if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) - set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) - endif() - - # If the debug & release library ends up being the same, omit the keywords - if(${Boost_${basename}_LIBRARY_RELEASE} STREQUAL ${Boost_${basename}_LIBRARY_DEBUG}) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) - set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) - endif() - - if(Boost_${basename}_LIBRARY) - set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY} CACHE FILEPATH "The Boost ${basename} library") - - # Remove superfluous "debug" / "optimized" keywords from - # Boost_LIBRARY_DIRS - foreach(_boost_my_lib ${Boost_${basename}_LIBRARY}) - get_filename_component(_boost_my_lib_path "${_boost_my_lib}" PATH) - list(APPEND Boost_LIBRARY_DIRS ${_boost_my_lib_path}) - endforeach() - list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) - - set(Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIRS} CACHE FILEPATH "Boost library directory") - set(Boost_${basename}_FOUND ON CACHE INTERNAL "Whether the Boost ${basename} library found") - endif() - - endif() - # Make variables changeble to the advanced user - mark_as_advanced( - Boost_${basename}_LIBRARY - Boost_${basename}_LIBRARY_RELEASE - Boost_${basename}_LIBRARY_DEBUG - ) -endmacro() - -#------------------------------------------------------------------------------- - -# -# Runs compiler with "-dumpversion" and parses major/minor -# version with a regex. -# -function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION) - - exec_program(${CMAKE_CXX_COMPILER} - ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion - OUTPUT_VARIABLE _boost_COMPILER_VERSION - ) - string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" - _boost_COMPILER_VERSION ${_boost_COMPILER_VERSION}) - - set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) -endfunction() - -# -# A convenience function for marking desired components -# as found or not -# -function(_Boost_MARK_COMPONENTS_FOUND _yes_or_no) - foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - set(Boost_${UPPERCOMPONENT}_FOUND ${_yes_or_no} CACHE INTERNAL "Whether the Boost ${COMPONENT} library found" FORCE) - endforeach() -endfunction() - -# -# Take a list of libraries with "thread" in it -# and prepend duplicates with "thread_${Boost_THREADAPI}" -# at the front of the list -# -function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) - set(_orig_libnames ${ARGN}) - string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}") - set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) -endfunction() - -# -# If a library is found, replace its cache entry with its REALPATH -# -function(_Boost_SWAP_WITH_REALPATH _library _docstring) - if(${_library}) - get_filename_component(_boost_filepathreal ${${_library}} REALPATH) - unset(${_library} CACHE) - set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") - endif() -endfunction() - -function(_Boost_CHECK_SPELLING _var) - if(${_var}) - string(TOUPPER ${_var} _var_UC) - message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") - endif() -endfunction() - -# Guesses Boost's compiler prefix used in built library names -# Returns the guess by setting the variable pointed to by _ret -function(_Boost_GUESS_COMPILER_PREFIX _ret) - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" - OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" - OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") - if(WIN32) - set (_boost_COMPILER "-iw") - else() - set (_boost_COMPILER "-il") - endif() - elseif (MSVC11) - set(_boost_COMPILER "-vc110") - elseif (MSVC10) - set(_boost_COMPILER "-vc100") - elseif (MSVC90) - set(_boost_COMPILER "-vc90") - elseif (MSVC80) - set(_boost_COMPILER "-vc80") - elseif (MSVC71) - set(_boost_COMPILER "-vc71") - elseif (MSVC70) # Good luck! - set(_boost_COMPILER "-vc7") # yes, this is correct - elseif (MSVC60) # Good luck! - set(_boost_COMPILER "-vc6") # yes, this is correct - elseif (BORLAND) - set(_boost_COMPILER "-bcb") - elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "SunPro") - set(_boost_COMPILER "-sw") - elseif (MINGW) - if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) - set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 - else() - _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) - set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") - endif() - elseif (UNIX) - if (CMAKE_COMPILER_IS_GNUCXX) - if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) - set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 - else() - _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) - # Determine which version of GCC we have. - if(APPLE) - if(Boost_MINOR_VERSION) - if(${Boost_MINOR_VERSION} GREATER 35) - # In Boost 1.36.0 and newer, the mangled compiler name used - # on Mac OS X/Darwin is "xgcc". - set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") - else() - # In Boost <= 1.35.0, there is no mangled compiler name for - # the Mac OS X/Darwin version of GCC. - set(_boost_COMPILER "") - endif() - else() - # We don't know the Boost version, so assume it's - # pre-1.36.0. - set(_boost_COMPILER "") - endif() - else() - set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") - endif() - endif() - endif () - else() - # TODO at least Boost_DEBUG here? - set(_boost_COMPILER "") - endif() - set(${_ret} ${_boost_COMPILER} PARENT_SCOPE) -endfunction() - -# -# End functions/macros -# -#------------------------------------------------------------------------------- - -#------------------------------------------------------------------------------- -# main. -#------------------------------------------------------------------------------- - -if(NOT DEFINED Boost_USE_MULTITHREADED) - set(Boost_USE_MULTITHREADED TRUE) -endif() - -# Check the version of Boost against the requested version. -if(Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) - message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") -endif() - -if(Boost_FIND_VERSION_EXACT) - # The version may appear in a directory with or without the patch - # level, even when the patch level is non-zero. - set(_boost_TEST_VERSIONS - "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}" - "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") -else() - # The user has not requested an exact version. Among known - # versions, find those that are acceptable to the user request. - set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} - "1.56.0" "1.56" "1.55.0" "1.55" "1.54.0" "1.54" - "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51" - "1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" - "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" - "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" - "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" - "1.34" "1.33.1" "1.33.0" "1.33") - set(_boost_TEST_VERSIONS) - if(Boost_FIND_VERSION) - set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") - # Select acceptable versions. - foreach(version ${_Boost_KNOWN_VERSIONS}) - if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}") - # This version is high enough. - list(APPEND _boost_TEST_VERSIONS "${version}") - elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99") - # This version is a short-form for the requested version with - # the patch level dropped. - list(APPEND _boost_TEST_VERSIONS "${version}") - endif() - endforeach() - else() - # Any version is acceptable. - set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}") - endif() -endif() - -# The reason that we failed to find Boost. This will be set to a -# user-friendly message when we fail to find some necessary piece of -# Boost. -set(Boost_ERROR_REASON) - - if(Boost_DEBUG) - # Output some of their choices - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_USE_MULTITHREADED = ${Boost_USE_MULTITHREADED}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_USE_STATIC_LIBS = ${Boost_USE_STATIC_LIBS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_USE_STATIC_RUNTIME = ${Boost_USE_STATIC_RUNTIME}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_ADDITIONAL_VERSIONS = ${Boost_ADDITIONAL_VERSIONS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}") - endif() - - if(WIN32) - # In windows, automatic linking is performed, so you do not have - # to specify the libraries. If you are linking to a dynamic - # runtime, then you can choose to link to either a static or a - # dynamic Boost library, the default is to do a static link. You - # can alter this for a specific library "whatever" by defining - # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be - # linked dynamically. Alternatively you can force all Boost - # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. - - # This feature can be disabled for Boost library "whatever" by - # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining - # BOOST_ALL_NO_LIB. - - # If you want to observe which libraries are being linked against - # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking - # code to emit a #pragma message each time a library is selected - # for linking. - set(Boost_LIB_DIAGNOSTIC_DEFINITIONS - "-DBOOST_LIB_DIAGNOSTIC" CACHE STRING "Boost diagnostic define") - endif() - - set(_boost_INCLUDE_SEARCH_DIRS_SYSTEM - C:/boost/include - C:/boost - "$ENV{ProgramFiles}/boost/include" - "$ENV{ProgramFiles}/boost" - /sw/local/include - ) - - _Boost_CHECK_SPELLING(Boost_ROOT) - _Boost_CHECK_SPELLING(Boost_LIBRARYDIR) - _Boost_CHECK_SPELLING(Boost_INCLUDEDIR) - - # If BOOST_ROOT was defined in the environment, use it. - if (NOT BOOST_ROOT AND NOT $ENV{Boost_DIR} STREQUAL "") - set(BOOST_ROOT $ENV{Boost_DIR}) - endif() - - # If BOOST_ROOT was defined in the environment, use it. - if (NOT BOOST_ROOT AND NOT $ENV{BOOST_ROOT} STREQUAL "") - set(BOOST_ROOT $ENV{BOOST_ROOT}) - endif() - - # If BOOSTROOT was defined in the environment, use it. - if (NOT BOOST_ROOT AND NOT $ENV{BOOSTROOT} STREQUAL "") - set(BOOST_ROOT $ENV{BOOSTROOT}) - endif() - - # If BOOST_INCLUDEDIR was defined in the environment, use it. - if( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) - set(BOOST_INCLUDEDIR $ENV{BOOST_INCLUDEDIR}) - endif() - - # If BOOST_LIBRARYDIR was defined in the environment, use it. - if( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) - set(BOOST_LIBRARYDIR $ENV{BOOST_LIBRARYDIR}) - endif() - - if( BOOST_ROOT ) - file(TO_CMAKE_PATH ${BOOST_ROOT} BOOST_ROOT) - endif() - - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Declared as CMake or Environmental Variables:") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " BOOST_ROOT = ${BOOST_ROOT}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " BOOST_INCLUDEDIR = ${BOOST_INCLUDEDIR}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " BOOST_LIBRARYDIR = ${BOOST_LIBRARYDIR}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") - endif() - - if( Boost_NO_SYSTEM_PATHS) - set(_boost_FIND_OPTIONS NO_CMAKE_SYSTEM_PATH) - else() - set(_boost_INCLUDE_SEARCH_DIRS ${_boost_INCLUDE_SEARCH_DIRS_SYSTEM}) - endif() - - if( BOOST_ROOT ) - set(_boost_INCLUDE_SEARCH_DIRS - ${BOOST_ROOT}/include - ${BOOST_ROOT} - ${_boost_INCLUDE_SEARCH_DIRS}) - endif() - - # prepend BOOST_INCLUDEDIR to search path if specified - if( BOOST_INCLUDEDIR ) - file(TO_CMAKE_PATH ${BOOST_INCLUDEDIR} BOOST_INCLUDEDIR) - set(_boost_INCLUDE_SEARCH_DIRS - ${BOOST_INCLUDEDIR} ${_boost_INCLUDE_SEARCH_DIRS}) - endif() - - # ------------------------------------------------------------------------ - # Search for Boost include DIR - # ------------------------------------------------------------------------ - # Try to find Boost by stepping backwards through the Boost versions - # we know about. - if( NOT Boost_INCLUDE_DIR ) - # Build a list of path suffixes for each version. - set(_boost_PATH_SUFFIXES) - foreach(_boost_VER ${_boost_TEST_VERSIONS}) - # Add in a path suffix, based on the required version, ideally - # we could read this from version.hpp, but for that to work we'd - # need to know the include dir already - set(_boost_BOOSTIFIED_VERSION) - - # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 - if(_boost_VER MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") - string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1_\\2_\\3" - _boost_BOOSTIFIED_VERSION ${_boost_VER}) - elseif(_boost_VER MATCHES "[0-9]+\\.[0-9]+") - string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1_\\2" - _boost_BOOSTIFIED_VERSION ${_boost_VER}) - endif() - - list(APPEND _boost_PATH_SUFFIXES "boost-${_boost_BOOSTIFIED_VERSION}") - list(APPEND _boost_PATH_SUFFIXES "boost_${_boost_BOOSTIFIED_VERSION}") - - endforeach() - - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Include debugging info:") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " _boost_INCLUDE_SEARCH_DIRS = ${_boost_INCLUDE_SEARCH_DIRS}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " _boost_PATH_SUFFIXES = ${_boost_PATH_SUFFIXES}") - endif() - - # Look for a standard boost header file. - find_path(Boost_INCLUDE_DIR - NAMES boost/config.hpp - HINTS ${_boost_INCLUDE_SEARCH_DIRS} - PATH_SUFFIXES ${_boost_PATH_SUFFIXES} - ${_boost_FIND_OPTIONS} - ) - endif() - - # ------------------------------------------------------------------------ - # Extract version information from version.hpp - # ------------------------------------------------------------------------ - - if(Boost_INCLUDE_DIR) - # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp - # Read the whole file: - # - set(BOOST_VERSION 0) - set(BOOST_LIB_VERSION "") - file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ") - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") - endif() - - string(REGEX REPLACE ".*#define BOOST_VERSION ([0-9]+).*" "\\1" Boost_VERSION "${_boost_VERSION_HPP_CONTENTS}") - string(REGEX REPLACE ".*#define BOOST_LIB_VERSION \"([0-9_]+)\".*" "\\1" Boost_LIB_VERSION "${_boost_VERSION_HPP_CONTENTS}") - unset(_boost_VERSION_HPP_CONTENTS) - - set(Boost_LIB_VERSION ${Boost_LIB_VERSION} CACHE INTERNAL "The library version string for boost libraries") - set(Boost_VERSION ${Boost_VERSION} CACHE INTERNAL "The version number for boost libraries") - - if(NOT "${Boost_VERSION}" STREQUAL "0") - math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") - math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") - math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") - - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}") - endif() - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "version.hpp reveals boost " - "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") - endif() - else() - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.") - endif() - - # ------------------------------------------------------------------------ - # Suffix initialization and compiler suffix detection. - # ------------------------------------------------------------------------ - - # Setting some more suffixes for the library - set(Boost_LIB_PREFIX "") - if ( WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) - set(Boost_LIB_PREFIX "lib") - endif() - - if (Boost_COMPILER) - set(_boost_COMPILER ${Boost_COMPILER}) - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "using user-specified Boost_COMPILER = ${_boost_COMPILER}") - endif() - else() - # Attempt to guess the compiler suffix - # NOTE: this is not perfect yet, if you experience any issues - # please report them and use the Boost_COMPILER variable - # to work around the problems. - _Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER) - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "guessed _boost_COMPILER = ${_boost_COMPILER}") - endif() - endif() - - set (_boost_MULTITHREADED "-mt") - if( NOT Boost_USE_MULTITHREADED ) - set (_boost_MULTITHREADED "") - endif() - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_MULTITHREADED = ${_boost_MULTITHREADED}") - endif() - - #====================== - # Systematically build up the Boost ABI tag - # http://boost.org/doc/libs/1_41_0/more/getting_started/windows.html#library-naming - set( _boost_RELEASE_ABI_TAG "-") - set( _boost_DEBUG_ABI_TAG "-") - # Key Use this library when: - # s linking statically to the C++ standard library and - # compiler runtime support libraries. - if(Boost_USE_STATIC_RUNTIME) - set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") - set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") - endif() - # g using debug versions of the standard and runtime - # support libraries - if(WIN32) - if(MSVC OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" - OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") - set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}g") - endif() - endif() - # y using special debug build of python - if(Boost_USE_DEBUG_PYTHON) - set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}y") - endif() - # d using a debug version of your code - set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}d") - # p using the STLport standard library rather than the - # default one supplied with your compiler - if(Boost_USE_STLPORT) - set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}p") - set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}p") - endif() - # n using the STLport deprecated "native iostreams" feature - if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) - set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}n") - set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}n") - endif() - - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}") - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_DEBUG_ABI_TAG = ${_boost_DEBUG_ABI_TAG}") - endif() - - # ------------------------------------------------------------------------ - # Begin finding boost libraries - # ------------------------------------------------------------------------ - - if(BOOST_ROOT) - set(_boost_LIBRARY_SEARCH_DIRS_ALWAYS - ${BOOST_ROOT}/lib - ${BOOST_ROOT}/stage/lib) - endif() - set(_boost_LIBRARY_SEARCH_DIRS_ALWAYS - ${_boost_LIBRARY_SEARCH_DIRS_ALWAYS} - ${Boost_INCLUDE_DIR}/lib - ${Boost_INCLUDE_DIR}/../lib - ${Boost_INCLUDE_DIR}/stage/lib - ) - set(_boost_LIBRARY_SEARCH_DIRS_SYSTEM - C:/boost/lib - C:/boost - "$ENV{ProgramFiles}/boost/boost_${Boost_MAJOR_VERSION}_${Boost_MINOR_VERSION}_${Boost_SUBMINOR_VERSION}/lib" - "$ENV{ProgramFiles}/boost/boost_${Boost_MAJOR_VERSION}_${Boost_MINOR_VERSION}/lib" - "$ENV{ProgramFiles}/boost/lib" - "$ENV{ProgramFiles}/boost" - /sw/local/lib - ) - set(_boost_LIBRARY_SEARCH_DIRS ${_boost_LIBRARY_SEARCH_DIRS_ALWAYS}) - if( Boost_NO_SYSTEM_PATHS ) - set(_boost_FIND_OPTIONS NO_CMAKE_SYSTEM_PATH) - else() - list(APPEND _boost_LIBRARY_SEARCH_DIRS ${_boost_LIBRARY_SEARCH_DIRS_SYSTEM}) - endif() - - # prepend BOOST_LIBRARYDIR to search path if specified - if( BOOST_LIBRARYDIR ) - file(TO_CMAKE_PATH ${BOOST_LIBRARYDIR} BOOST_LIBRARYDIR) - set(_boost_LIBRARY_SEARCH_DIRS - ${BOOST_LIBRARYDIR} ${_boost_LIBRARY_SEARCH_DIRS}) - endif() - - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "_boost_LIBRARY_SEARCH_DIRS = ${_boost_LIBRARY_SEARCH_DIRS}") - endif() - - # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES - if( Boost_USE_STATIC_LIBS ) - set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) - endif() - endif() - - # We want to use the tag inline below without risking double dashes - if(_boost_RELEASE_ABI_TAG) - if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") - set(_boost_RELEASE_ABI_TAG "") - endif() - endif() - if(_boost_DEBUG_ABI_TAG) - if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") - set(_boost_DEBUG_ABI_TAG "") - endif() - endif() - - # The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled - # on WIN32 was to: - # 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) - # 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) - # We maintain this behavior since changing it could break people's builds. - # To disable the ambiguous behavior, the user need only - # set Boost_USE_STATIC_RUNTIME either ON or OFF. - set(_boost_STATIC_RUNTIME_WORKAROUND false) - if(WIN32 AND Boost_USE_STATIC_LIBS) - if(NOT DEFINED Boost_USE_STATIC_RUNTIME) - set(_boost_STATIC_RUNTIME_WORKAROUND true) - endif() - endif() - - # On versions < 1.35, remove the System library from the considered list - # since it wasn't added until 1.35. - if(Boost_VERSION AND Boost_FIND_COMPONENTS) - if(Boost_VERSION LESS 103500) - list(REMOVE_ITEM Boost_FIND_COMPONENTS system) - endif() - endif() - - foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} UPPERCOMPONENT) - set( Boost_${UPPERCOMPONENT}_LIBRARY "Boost_${UPPERCOMPONENT}_LIBRARY-NOTFOUND" ) - set( Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE-NOTFOUND" ) - set( Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG-NOTFOUND") - - set( _boost_docstring_release "Boost ${COMPONENT} library (release)") - set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") - - # - # Find RELEASE libraries - # - set(_boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT} ) - if(_boost_STATIC_RUNTIME_WORKAROUND) - set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") - list(APPEND _boost_RELEASE_NAMES - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) - endif() - if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") - _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) - endif() - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") - endif() - find_library(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE - NAMES ${_boost_RELEASE_NAMES} - HINTS ${_boost_LIBRARY_SEARCH_DIRS} - ${_boost_FIND_OPTIONS} - DOC "${_boost_docstring_release}" - ) - - # - # Find DEBUG libraries - # - set(_boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED} - ${Boost_LIB_PREFIX}boost_${COMPONENT} ) - if(_boost_STATIC_RUNTIME_WORKAROUND) - set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") - list(APPEND _boost_DEBUG_NAMES - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} - ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) - endif() - if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") - _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) - endif() - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") - endif() - find_library(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG - NAMES ${_boost_DEBUG_NAMES} - HINTS ${_boost_LIBRARY_SEARCH_DIRS} - ${_boost_FIND_OPTIONS} - DOC "${_boost_docstring_debug}" - ) - - if(Boost_REALPATH) - _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") - _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) - endif() - - _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) - - endforeach() - - # Restore the original find library ordering - if( Boost_USE_STATIC_LIBS ) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) - endif() - - # ------------------------------------------------------------------------ - # End finding boost libraries - # ------------------------------------------------------------------------ - - # ------------------------------------------------------------------------ - # Begin long process of determining Boost_FOUND, starting with version - # number checks, followed by - # TODO: Ideally the version check logic should happen prior to searching - # for libraries... - # ------------------------------------------------------------------------ - - set(Boost_INCLUDE_DIRS - ${Boost_INCLUDE_DIR} - ) - - set(Boost_FOUND FALSE) - if(Boost_INCLUDE_DIR) - set( Boost_FOUND TRUE ) - - if(Boost_MAJOR_VERSION LESS "${Boost_FIND_VERSION_MAJOR}" ) - set( Boost_FOUND FALSE ) - set(_Boost_VERSION_AGE "old") - elseif(Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) - if(Boost_MINOR_VERSION LESS "${Boost_FIND_VERSION_MINOR}" ) - set( Boost_FOUND FALSE ) - set(_Boost_VERSION_AGE "old") - elseif(Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) - if( Boost_FIND_VERSION_PATCH AND Boost_SUBMINOR_VERSION LESS "${Boost_FIND_VERSION_PATCH}" ) - set( Boost_FOUND FALSE ) - set(_Boost_VERSION_AGE "old") - endif() - endif() - endif() - - if (NOT Boost_FOUND) - _Boost_MARK_COMPONENTS_FOUND(OFF) - endif() - - if (Boost_FOUND AND Boost_FIND_VERSION_EXACT) - # If the user requested an exact version of Boost, check - # that. We already know that the Boost version we have is >= the - # requested version. - set(_Boost_VERSION_AGE "new") - - # If the user didn't specify a patchlevel, it's 0. - if (NOT Boost_FIND_VERSION_PATCH) - set(Boost_FIND_VERSION_PATCH 0) - endif () - - # We'll set Boost_FOUND true again if we have an exact version match. - set(Boost_FOUND FALSE) - _Boost_MARK_COMPONENTS_FOUND(OFF) - if(Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) - if(Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) - if(Boost_SUBMINOR_VERSION EQUAL "${Boost_FIND_VERSION_PATCH}" ) - set( Boost_FOUND TRUE ) - _Boost_MARK_COMPONENTS_FOUND(ON) - endif() - endif() - endif() - endif () - - if(NOT Boost_FOUND) - # State that we found a version of Boost that is too new or too old. - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") - if (Boost_FIND_VERSION_PATCH) - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}.${Boost_FIND_VERSION_PATCH}") - endif () - if (NOT Boost_FIND_VERSION_EXACT) - set(Boost_ERROR_REASON "${Boost_ERROR_REASON} (or newer)") - endif () - set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.") - endif () - - # Always check for missing components - set(_boost_CHECKED_COMPONENT FALSE) - set(_Boost_MISSING_COMPONENTS "") - foreach(COMPONENT ${Boost_FIND_COMPONENTS}) - string(TOUPPER ${COMPONENT} COMPONENT) - set(_boost_CHECKED_COMPONENT TRUE) - if(NOT Boost_${COMPONENT}_FOUND) - string(TOLOWER ${COMPONENT} COMPONENT) - list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT}) - set( Boost_FOUND FALSE) - endif() - endforeach() - - if(Boost_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] Boost_FOUND = ${Boost_FOUND}") - endif() - - if (_Boost_MISSING_COMPONENTS) - # We were unable to find some libraries, so generate a sensible - # error message that lists the libraries we were unable to find. - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}\nThe following Boost libraries could not be found:\n") - foreach(COMPONENT ${_Boost_MISSING_COMPONENTS}) - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON} boost_${COMPONENT}\n") - endforeach() - - list(LENGTH Boost_FIND_COMPONENTS Boost_NUM_COMPONENTS_WANTED) - list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS) - if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") - else () - set(Boost_ERROR_REASON - "${Boost_ERROR_REASON}Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") - endif () - endif () - - if( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) - # Compatibility Code for backwards compatibility with CMake - # 2.4's FindBoost module. - - # Look for the boost library path. - # Note that the user may not have installed any libraries - # so it is quite possible the Boost_LIBRARY_DIRS may not exist. - set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) - - if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") - get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - endif() - - if("${_boost_LIB_DIR}" MATCHES "/include$") - # Strip off the trailing "/include" in the path. - get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) - endif() - - if(EXISTS "${_boost_LIB_DIR}/lib") - set(_boost_LIB_DIR ${_boost_LIB_DIR}/lib) - else() - if(EXISTS "${_boost_LIB_DIR}/stage/lib") - set(_boost_LIB_DIR ${_boost_LIB_DIR}/stage/lib) - else() - set(_boost_LIB_DIR "") - endif() - endif() - - if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") - set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR} CACHE FILEPATH "Boost library directory") - endif() - - endif() - - else() - set( Boost_FOUND FALSE) - endif() - - # ------------------------------------------------------------------------ - # Notification to end user about what was found - # ------------------------------------------------------------------------ - - if(Boost_FOUND) - if(NOT Boost_FIND_QUIETLY) - message(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") - if(Boost_FIND_COMPONENTS) - message(STATUS "Found the following Boost libraries:") - endif() - endif() - foreach( COMPONENT ${Boost_FIND_COMPONENTS} ) - string( TOUPPER ${COMPONENT} UPPERCOMPONENT ) - if( Boost_${UPPERCOMPONENT}_FOUND ) - if(NOT Boost_FIND_QUIETLY) - message (STATUS " ${COMPONENT}") - endif() - set(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${UPPERCOMPONENT}_LIBRARY}) - endif() - endforeach() - else() - if(Boost_FIND_REQUIRED) - message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}") - else() - if(NOT Boost_FIND_QUIETLY) - # we opt not to automatically output Boost_ERROR_REASON here as - # it could be quite lengthy and somewhat imposing in its requests - # Since Boost is not always a required dependency we'll leave this - # up to the end-user. - if(Boost_DEBUG OR Boost_DETAILED_FAILURE_MSG) - message(STATUS "Could NOT find Boost\n${Boost_ERROR_REASON}") - else() - message(STATUS "Could NOT find Boost") - endif() - endif() - endif() - endif() - - # show the Boost_INCLUDE_DIRS AND Boost_LIBRARIES variables only in the advanced view - mark_as_advanced(Boost_INCLUDE_DIR - Boost_INCLUDE_DIRS - Boost_LIBRARY_DIRS - ) diff --git a/cmake_modules/FindCEGUI.cmake b/cmake_modules/FindCEGUI.cmake deleted file mode 100644 index e94f48112f2..00000000000 --- a/cmake_modules/FindCEGUI.cmake +++ /dev/null @@ -1,180 +0,0 @@ - # Locate CEGUI (Made for CEGUI 7.5) - # - # This module defines - # CEGUI_FOUND, if false, do not try to link to CEGUI - # CEGUI_LIBRARY, where to find the librarys - # CEGUI_INCLUDE_DIR, where to find the headers - # - # $CEGUIDIR is an environment variable that would - # correspond to the ./configure --prefix=$CEGUIDIR - # - # There are several COMPONENTS that can be included: - # NULL, OPENGL, DIRECT3D9, DIRECT3D10, DIRECT3D11, DIRECTFB, OGRE, IRRLICHT - # Selecting no render as COMPONENT will create a error massage! - # - # 2011-07-21 Created by Frederik vom Hofe using the findSFML.cmake versions from David Guthrie with code from Robert Osfield. - - SET(CEGUI_FOUND "YES") - SET(CEGUI_LIBRARY "") - SET(CEGUI_INCLUDE_DIR "") - - if(NOT DEFINED FIND_CEGUI_VERSION) - set(FIND_CEGUI_VERSION 0) - endif() - - SET( CEGUIDIR $ENV{CEGUIDIR} ) - IF((WIN32 OR WIN64) AND NOT(CYGWIN)) - # Convert backslashes to slashes - STRING(REGEX REPLACE "\\\\" "/" CEGUIDIR "${CEGUIDIR}") - ENDIF() - - - #To always have the right case sensitive name we use this list and a helper macro: - SET(RENDER_NAME - Null - OpenGL - Direct3D9 - Direct3D10 - Direct3D11 - DirectFB - Ogre - Irrlicht - ) - - MACRO(HELPER_GET_CASE_FROM_LIST SEARCHSTR LOOKUPLIST RESULTSTR) - SET(${RESULTSTR} ${SEARCHSTR}) #default return value if nothing is found - FOREACH(LOOP_S IN LISTS ${LOOKUPLIST}) - string(TOLOWER ${LOOP_S} LOOP_S_LOWER) - string(TOLOWER ${SEARCHSTR} LOOP_SEARCHSTR_LOWER) - string(COMPARE EQUAL ${LOOP_S_LOWER} ${LOOP_SEARCHSTR_LOWER} LOOP_STR_COMPARE) - IF(LOOP_STR_COMPARE) - SET(${RESULTSTR} ${LOOP_S}) - ENDIF() - ENDFOREACH() - ENDMACRO() - - #********** First we locate the include directorys ********** ********** ********** ********** - SET( CEGUI_INCLUDE_SEARCH_DIR - "${CEGUI_ROOT}/include" - "${CEGUI_ROOT}/include/cegui-${FIND_CEGUI_VERSION}" - "${CEGUIDIR}/include" - "${CEGUIDIR}/include/cegui-${FIND_CEGUI_VERSION}" - - ~/Library/Frameworks - /Library/Frameworks - /usr/local/include - /usr/local/cegui-${FIND_CEGUI_VERSION}/include - /usr/local/include/cegui-${FIND_CEGUI_VERSION} - /usr/include - /usr/include/cegui-${FIND_CEGUI_VERSION} - /sw/include # Fink - /sw/include/cegui-${FIND_CEGUI_VERSION} - /opt/local/include # DarwinPorts - /opt/local/include/cegui-${FIND_CEGUI_VERSION} - /opt/csw/include # Blastwave - /opt/csw/include/cegui-${FIND_CEGUI_VERSION} - /opt/include - /opt/include/cegui-${FIND_CEGUI_VERSION} - /usr/freeware/include - /usr/freeware/include/cegui-${FIND_CEGUI_VERSION} - ) - - #helper - MACRO(FIND_PATH_HELPER FILENAME DIR SUFFIX USERENDERER) - FIND_PATH(${FILENAME}_DIR ${FILENAME} PATHS ${${DIR}} PATH_SUFFIXES ${SUFFIX}) - IF(NOT ${FILENAME}_DIR) - MESSAGE("Could not located ${FILENAME}") - SET(CEGUI_FOUND "NO") - ELSE() - message(STATUS ${USERENDERER}) - IF (${ARGC} GREATER 4) - LIST(APPEND CEGUI_INCLUDE_DIR ${${FILENAME}_DIR}) - ELSE() - - LIST(APPEND CEGUI_INCLUDE_DIR ${${FILENAME}_DIR}/../) - ENDIF() - ENDIF() - ENDMACRO() - FIND_PATH_HELPER(CEGUI.h CEGUI_INCLUDE_SEARCH_DIR CEGUI "") - - IF("${CEGUI_FIND_COMPONENTS}" STREQUAL "") - MESSAGE("ERROR: No CEGUI renderer selected. \n\nSelect a renderer by including it's name in the component list:\n\ne.g. Find_Package(CEGUI REQUIRED COMPONENTS OPENGL)\n\nCEGUI renderers:") - FOREACH(LOOP_S IN LISTS RENDER_NAME) - MESSAGE("${LOOP_S}") - ENDFOREACH() - MESSAGE("\n") - MESSAGE(SEND_ERROR "Select at last one renderer!" ) - ENDIF() - - FOREACH(COMPONENT ${CEGUI_FIND_COMPONENTS}) - HELPER_GET_CASE_FROM_LIST( ${COMPONENT} RENDER_NAME COMPONENT_CASE) - FIND_PATH_HELPER( "Renderer.h" "CEGUI_INCLUDE_SEARCH_DIR" "CEGUI/RendererModules/${COMPONENT_CASE}/;RendererModules/${COMPONENT_CASE}/" "" TRUE ) - ENDFOREACH(COMPONENT) - - IF (APPLE) - FIND_PATH(CEGUI_FRAMEWORK_DIR CEGUI.h - PATHS - ~/Library/Frameworks/CEGUI.framework/Headers - /Library/Frameworks/CEGUI.framework/Headers - ${DELTA3D_EXT_DIR}/Frameworks/CEGUI.framework/Headers - ) - ENDIF (APPLE) - - IF(CEGUI_FRAMEWORK_DIR) - LIST(APPEND CEGUI_INCLUDE_DIR ${CEGUI_FRAMEWORK_DIR}) - ENDIF() - - - #********** Then we locate the Librarys ********** ********** ********** ********** - SET( CEGUI_LIBRARY_SEARCH_DIR - ${CEGUIDIR}/lib - "${CEGUI_ROOT}/lib" - "${CEGUIDIR}" - ~/Library/Frameworks - /Library/Frameworks - /usr/local/lib - /usr/lib - /sw/lib - /opt/local/lib - /opt/csw/lib - /opt/lib - [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;CEGUI_ROOT]/lib - /usr/freeware/lib64 - ) - - #helper - MACRO(FIND_LIBRARY_HELPER FILENAME DIR) - FIND_LIBRARY(${FILENAME}_DIR NAMES ${FILENAME} PATHS ${${DIR}}) - IF(NOT ${FILENAME}_DIR) - MESSAGE("Could not located ${FILENAME}") - SET(CEGUI_FOUND "NO") - ELSE() - LIST(APPEND CEGUI_LIBRARY ${${FILENAME}_DIR}) - ENDIF() - ENDMACRO() - - IF(CMAKE_BUILD_TYPE MATCHES "^([Dd][Ee][Bb][Uu][Gg])$") - FIND_LIBRARY_HELPER( CEGUIBase-${FIND_CEGUI_VERSION}_d CEGUI_LIBRARY_SEARCH_DIR ) - ELSE() - FIND_LIBRARY_HELPER( CEGUIBase-${FIND_CEGUI_VERSION} CEGUI_LIBRARY_SEARCH_DIR ) - ENDIF() - - - FOREACH(COMPONENT ${CEGUI_FIND_COMPONENTS}) - HELPER_GET_CASE_FROM_LIST( ${COMPONENT} RENDER_NAME COMPONENT_CASE) - IF(CMAKE_BUILD_TYPE MATCHES "^([Dd][Ee][Bb][Uu][Gg])$") - FIND_LIBRARY_HELPER( CEGUI${COMPONENT_CASE}Renderer-${FIND_CEGUI_VERSION}_d "CEGUI_LIBRARY_SEARCH_DIR" CEGUI) - ELSE() - FIND_LIBRARY_HELPER( CEGUI${COMPONENT_CASE}Renderer-${FIND_CEGUI_VERSION} "CEGUI_LIBRARY_SEARCH_DIR" CEGUI) - ENDIF() - - ENDFOREACH(COMPONENT) - - #********** And we are done ********** ********** ********** ********** ********** ********** ********** ********** - - IF(NOT CEGUI_FOUND) - MESSAGE(SEND_ERROR "Error(s) during CEGUI detection!") - ENDIF() - - INCLUDE(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(CEGUI DEFAULT_MSG CEGUI_LIBRARY CEGUI_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake_modules/FindFFMPEG.cmake b/cmake_modules/FindFFMPEG.cmake deleted file mode 100644 index bebee2b850d..00000000000 --- a/cmake_modules/FindFFMPEG.cmake +++ /dev/null @@ -1,164 +0,0 @@ -# vim: ts=2 sw=2 -# - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC) -# -# Once done this will define -# FFMPEG_FOUND - System has the all required components. -# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. -# FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. -# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. -# -# For each of the components it will additionaly set. -# - AVCODEC -# - AVDEVICE -# - AVFORMAT -# - AVUTIL -# - POSTPROCESS -# - SWSCALE -# - SWRESAMPLE -# the following variables will be defined -# _FOUND - System has -# _INCLUDE_DIRS - Include directory necessary for using the headers -# _LIBRARIES - Link these to use -# _DEFINITIONS - Compiler switches required for using -# _VERSION - The components version -# -# Copyright (c) 2006, Matthias Kretz, -# Copyright (c) 2008, Alexander Neundorf, -# Copyright (c) 2011, Michael Jansen, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -include(FindPackageHandleStandardArgs) - -# The default components were taken from a survey over other FindFFMPEG.cmake files -if (NOT FFmpeg_FIND_COMPONENTS) - set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) -endif () - -# -### Macro: set_component_found -# -# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. -# -macro(set_component_found _component ) - if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) - # message(STATUS " - ${_component} found.") - set(${_component}_FOUND TRUE) - else () - # message(STATUS " - ${_component} not found.") - endif () -endmacro() - -# -### Macro: find_component -# -# Checks for the given component by invoking pkgconfig and then looking up the libraries and -# include directories. -# -macro(find_component _component _pkgconfig _library _header) - - if (NOT WIN32) - # use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(PC_${_component} ${_pkgconfig}) - endif () - endif (NOT WIN32) - - find_path(${_component}_INCLUDE_DIRS ${_header} - HINTS - ${FFMPEGSDK_INC} - ${PC_LIB${_component}_INCLUDEDIR} - ${PC_LIB${_component}_INCLUDE_DIRS} - ${MINGW_ENV}/install/include - ${MINGW_ENV}/install/include/ogre-ffmpeg - PATH_SUFFIXES - ffmpeg - ) - - find_library(${_component}_LIBRARIES NAMES ${_library} - HINTS - ${FFMPEGSDK_LIB} - ${PC_LIB${_component}_LIBDIR} - ${PC_LIB${_component}_LIBRARY_DIRS} - ${MINGW_ENV}/install/lib - ${MINGW_ENV}/install/lib/Debug - ${MINGW_ENV}/install/lib/Release - ) - - set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") - set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") - - set_component_found(${_component}) - - mark_as_advanced( - ${_component}_INCLUDE_DIRS - ${_component}_LIBRARIES - ${_component}_DEFINITIONS - ${_component}_VERSION) - -endmacro() - - -# Check for cached results. If there are skip the costly part. -if (NOT FFMPEG_LIBRARIES) - - set (FFMPEGSDK $ENV{FFMPEG_HOME}) - if (FFMPEGSDK) - set (FFMPEGSDK_INC "${FFMPEGSDK}/include") - set (FFMPEGSDK_LIB "${FFMPEGSDK}/lib") - endif () - - # Check for all possible component. - find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) - find_component(AVFORMAT libavformat avformat libavformat/avformat.h) - find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) - find_component(AVUTIL libavutil avutil libavutil/avutil.h) - find_component(SWSCALE libswscale swscale libswscale/swscale.h) - find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h) - find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h) - find_component(AVRESAMPLE libavresample avresample libavresample/avresample.h) - - # Check if the required components were found and add their stuff to the FFMPEG_* vars. - foreach (_component ${FFmpeg_FIND_COMPONENTS}) - if (${_component}_FOUND) - # message(STATUS "Required component ${_component} present.") - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES}) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS}) - list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) - else () - # message(STATUS "Required component ${_component} missing.") - endif () - endforeach () - - # Build the include path with duplicates removed. - if (FFMPEG_INCLUDE_DIRS) - list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) - endif () - - # cache the vars. - set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) - set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) - - mark_as_advanced(FFMPEG_INCLUDE_DIRS - FFMPEG_LIBRARIES - FFMPEG_DEFINITIONS) - -endif () - -# Now set the noncached _FOUND vars for the components. -foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE SWRESAMPLE AVRESAMPLE) - set_component_found(${_component}) -endforeach () - -# Compile the list of required vars -set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) -foreach (_component ${FFmpeg_FIND_COMPONENTS}) - list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) -endforeach () - -# Give a nice error message if some of the required vars are missing. -find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS}) diff --git a/cmake_modules/FindFreetype.cmake b/cmake_modules/FindFreetype.cmake deleted file mode 100644 index 34a0de67fe4..00000000000 --- a/cmake_modules/FindFreetype.cmake +++ /dev/null @@ -1,49 +0,0 @@ -# - Try to find FreeType -# Once done, this will define -# -# FREETYPE_FOUND - system has FreeType -# FREETYPE_INCLUDE_DIRS - the FreeType include directories -# FREETYPE_LIBRARIES - link these to use FreeType - -include(FindPkgMacros) -findpkg_begin(FREETYPE) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(FREETYPE_HOME) - -# construct search paths -set(FREETYPE_PREFIX_PATH ${FREETYPE_HOME} ${ENV_FREETYPE_HOME}) -create_search_paths(FREETYPE) -# redo search if prefix path changed -clear_if_changed(FREETYPE_PREFIX_PATH - FREETYPE_LIBRARY_FWK - FREETYPE_LIBRARY_REL - FREETYPE_LIBRARY_DBG - FREETYPE_INCLUDE_DIR -) - -set(FREETYPE_LIBRARY_NAMES freetype2311 freetype239 freetype238 freetype235 freetype219 freetype) -get_debug_names(FREETYPE_LIBRARY_NAMES) - -use_pkgconfig(FREETYPE_PKGC freetype2) - -# prefer static library over framework -set(CMAKE_FIND_FRAMEWORK "LAST") - -findpkg_framework(FREETYPE) -message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}") - -find_path(FREETYPE_INCLUDE_DIR NAMES freetype/freetype.h HINTS ${FREETYPE_INC_SEARCH_PATH} ${FREETYPE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES freetype2) -find_path(FREETYPE_FT2BUILD_INCLUDE_DIR NAMES ft2build.h HINTS ${FREETYPE_INC_SEARCH_PATH} ${FREETYPE_PKGC_INCLUDE_DIRS}) -find_library(FREETYPE_LIBRARY_REL NAMES ${FREETYPE_LIBRARY_NAMES} HINTS ${FREETYPE_LIB_SEARCH_PATH} ${FREETYPE_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(FREETYPE_LIBRARY_DBG NAMES ${FREETYPE_LIBRARY_NAMES_DBG} HINTS ${FREETYPE_LIB_SEARCH_PATH} ${FREETYPE_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(FREETYPE_LIBRARY) - -findpkg_finish(FREETYPE) -mark_as_advanced(FREETYPE_FT2BUILD_INCLUDE_DIR) -if (NOT FREETYPE_FT2BUILD_INCLUDE_DIR STREQUAL FREETYPE_INCLUDE_DIR) - set(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS} ${FREETYPE_FT2BUILD_INCLUDE_DIR}) -endif () - -# Reset framework finding -set(CMAKE_FIND_FRAMEWORK "FIRST") diff --git a/cmake_modules/FindOGRE.cmake b/cmake_modules/FindOGRE.cmake deleted file mode 100644 index 923dbc87790..00000000000 --- a/cmake_modules/FindOGRE.cmake +++ /dev/null @@ -1,546 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OGRE -# If you have multiple versions of Ogre installed, use the CMake or -# the environment variable OGRE_HOME to point to the path where the -# desired Ogre version can be found. -# By default this script will look for a dynamic Ogre build. If you -# need to link against static Ogre libraries, set the CMake variable -# OGRE_STATIC to TRUE. -# -# Once done, this will define -# -# OGRE_FOUND - system has OGRE -# OGRE_INCLUDE_DIRS - the OGRE include directories -# OGRE_LIBRARIES - link these to use the OGRE core -# OGRE_BINARY_REL - location of the main Ogre binary (win32 non-static only, release) -# OGRE_BINARY_DBG - location of the main Ogre binaries (win32 non-static only, debug) -# -# Additionally this script searches for the following optional -# parts of the Ogre package: -# Plugin_BSPSceneManager, Plugin_CgProgramManager, -# Plugin_OctreeSceneManager, Plugin_OctreeZone, -# Plugin_ParticleFX, Plugin_PCZSceneManager, -# RenderSystem_GL, RenderSystem_Direct3D9, -# Paging, Terrain -# -# For each of these components, the following variables are defined: -# -# OGRE_${COMPONENT}_FOUND - ${COMPONENT} is available -# OGRE_${COMPONENT}_INCLUDE_DIRS - additional include directories for ${COMPONENT} -# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT} -# OGRE_${COMPONENT}_BINARY_REL - location of the component binary (win32 non-static only, release) -# OGRE_${COMPONENT}_BINARY_DBG - location of the component binary (win32 non-static only, debug) -# -# Finally, the following variables are defined: -# -# OGRE_PLUGIN_DIR_REL - The directory where the release versions of -# the OGRE plugins are located -# OGRE_PLUGIN_DIR_DBG - The directory where the debug versions of -# the OGRE plugins are located -# OGRE_MEDIA_DIR - The directory where the OGRE sample media is -# located, if available - -include(FindPkgMacros) -include(PreprocessorUtils) -findpkg_begin(OGRE) - - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(OGRE_HOME) -getenv_path(OGRE_SDK) -getenv_path(OGRE_SOURCE) -getenv_path(OGRE_BUILD) -getenv_path(OGRE_DEPENDENCIES_DIR) -getenv_path(PROGRAMFILES) - -# Determine whether to search for a dynamic or static build -if (OGRE_STATIC) - set(OGRE_LIB_SUFFIX "Static") -else () - set(OGRE_LIB_SUFFIX "") -endif () - - -if(APPLE AND NOT OGRE_BUILD_PLATFORM_APPLE_IOS) - set(OGRE_LIBRARY_NAMES "Ogre${OGRE_LIB_SUFFIX}") -else() - set(OGRE_LIBRARY_NAMES "OgreMain${OGRE_LIB_SUFFIX}") -endif() -get_debug_names(OGRE_LIBRARY_NAMES) - -# construct search paths from environmental hints and -# OS specific guesses -if (WIN32) - set(OGRE_PREFIX_GUESSES - ${ENV_PROGRAMFILES}/OGRE - ${MINGW_ENV}/OgreSDK - ) -elseif (UNIX) - set(OGRE_PREFIX_GUESSES - /opt/ogre - /opt/OGRE - /usr/lib${LIB_SUFFIX}/ogre - /usr/lib${LIB_SUFFIX}/OGRE - /usr/local/lib${LIB_SUFFIX}/ogre - /usr/local/lib${LIB_SUFFIX}/OGRE - $ENV{HOME}/ogre - $ENV{HOME}/OGRE - ) -endif () -set(OGRE_PREFIX_PATH - ${OGRE_HOME} ${OGRE_SDK} ${ENV_OGRE_HOME} ${ENV_OGRE_SDK} - ${OGRE_PREFIX_GUESSES} -) -create_search_paths(OGRE) -# If both OGRE_BUILD and OGRE_SOURCE are set, prepare to find Ogre in a build dir -set(OGRE_PREFIX_SOURCE ${OGRE_SOURCE} ${ENV_OGRE_SOURCE}) -set(OGRE_PREFIX_BUILD ${OGRE_BUILD} ${ENV_OGRE_BUILD}) -set(OGRE_PREFIX_DEPENDENCIES_DIR ${OGRE_DEPENDENCIES_DIR} ${ENV_OGRE_DEPENDENCIES_DIR}) -if (OGRE_PREFIX_SOURCE AND OGRE_PREFIX_BUILD) - foreach(dir ${OGRE_PREFIX_SOURCE}) - set(OGRE_INC_SEARCH_PATH ${dir}/OgreMain/include ${dir}/Dependencies/include ${dir}/iOSDependencies/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${dir}/lib ${dir}/Dependencies/lib ${dir}/iOSDependencies/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH}) - endforeach(dir) - foreach(dir ${OGRE_PREFIX_BUILD}) - set(OGRE_INC_SEARCH_PATH ${dir}/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${dir}/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/bin ${OGRE_BIN_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH}) - endforeach(dir) - - if (OGRE_PREFIX_DEPENDENCIES_DIR) - set(OGRE_INC_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/include ${OGRE_INC_SEARCH_PATH}) - set(OGRE_LIB_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/lib ${OGRE_LIB_SEARCH_PATH}) - set(OGRE_BIN_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/bin ${OGRE_BIN_SEARCH_PATH}) - endif() -else() - set(OGRE_PREFIX_SOURCE "NOTFOUND") - set(OGRE_PREFIX_BUILD "NOTFOUND") -endif () - -# redo search if any of the environmental hints changed -set(OGRE_COMPONENTS Paging Terrain - Plugin_BSPSceneManager Plugin_CgProgramManager Plugin_OctreeSceneManager - Plugin_OctreeZone Plugin_PCZSceneManager Plugin_ParticleFX - RenderSystem_Direct3D11 RenderSystem_Direct3D9 RenderSystem_GL RenderSystem_GLES RenderSystem_GLES2) -set(OGRE_RESET_VARS - OGRE_CONFIG_INCLUDE_DIR OGRE_INCLUDE_DIR - OGRE_LIBRARY_FWK OGRE_LIBRARY_REL OGRE_LIBRARY_DBG - OGRE_PLUGIN_DIR_DBG OGRE_PLUGIN_DIR_REL OGRE_MEDIA_DIR) -foreach (comp ${OGRE_COMPONENTS}) - set(OGRE_RESET_VARS ${OGRE_RESET_VARS} - OGRE_${comp}_INCLUDE_DIR OGRE_${comp}_LIBRARY_FWK - OGRE_${comp}_LIBRARY_DBG OGRE_${comp}_LIBRARY_REL - ) -endforeach (comp) -set(OGRE_PREFIX_WATCH ${OGRE_PREFIX_PATH} ${OGRE_PREFIX_SOURCE} ${OGRE_PREFIX_BUILD}) -clear_if_changed(OGRE_PREFIX_WATCH ${OGRE_RESET_VARS}) - -if(NOT OGRE_BUILD_PLATFORM_APPLE_IOS) - # try to locate Ogre via pkg-config - use_pkgconfig(OGRE_PKGC "OGRE${OGRE_LIB_SUFFIX}") - - # try to find framework on OSX - findpkg_framework(OGRE) -else() - set(OGRE_LIBRARY_FWK "") -endif() - -# locate Ogre include files -find_path(OGRE_CONFIG_INCLUDE_DIR NAMES OgreBuildSettings.h HINTS ${OGRE_INC_SEARCH_PATH} ${OGRE_FRAMEWORK_INCLUDES} ${OGRE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES "OGRE") -find_path(OGRE_INCLUDE_DIR NAMES OgreRoot.h HINTS ${OGRE_CONFIG_INCLUDE_DIR} ${OGRE_INC_SEARCH_PATH} ${OGRE_FRAMEWORK_INCLUDES} ${OGRE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES "OGRE") -set(OGRE_INCOMPATIBLE FALSE) - -if (OGRE_INCLUDE_DIR) - if (NOT OGRE_CONFIG_INCLUDE_DIR) - set(OGRE_CONFIG_INCLUDE_DIR ${OGRE_INCLUDE_DIR}) - endif () - # determine Ogre version - file(READ ${OGRE_INCLUDE_DIR}/OgrePrerequisites.h OGRE_TEMP_VERSION_CONTENT) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MAJOR OGRE_VERSION_MAJOR) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MINOR OGRE_VERSION_MINOR) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_PATCH OGRE_VERSION_PATCH) - get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_NAME OGRE_VERSION_NAME) - set(OGRE_VERSION "${OGRE_VERSION_MAJOR}.${OGRE_VERSION_MINOR}.${OGRE_VERSION_PATCH}") - pkg_message(OGRE "Found Ogre ${OGRE_VERSION_NAME} (${OGRE_VERSION})") - - # determine configuration settings - set(OGRE_CONFIG_HEADERS - ${OGRE_CONFIG_INCLUDE_DIR}/OgreBuildSettings.h - ${OGRE_CONFIG_INCLUDE_DIR}/OgreConfig.h - ) - foreach(CFG_FILE ${OGRE_CONFIG_HEADERS}) - if (EXISTS ${CFG_FILE}) - set(OGRE_CONFIG_HEADER ${CFG_FILE}) - break() - endif() - endforeach() - if (OGRE_CONFIG_HEADER) - file(READ ${OGRE_CONFIG_HEADER} OGRE_TEMP_CONFIG_CONTENT) - has_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_STATIC_LIB OGRE_CONFIG_STATIC) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_THREAD_SUPPORT OGRE_CONFIG_THREADS) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_THREAD_PROVIDER OGRE_CONFIG_THREAD_PROVIDER) - get_preprocessor_entry(OGRE_TEMP_CONFIG_CONTENT OGRE_NO_FREEIMAGE OGRE_CONFIG_FREEIMAGE) - if (OGRE_CONFIG_STATIC AND OGRE_STATIC) - elseif (OGRE_CONFIG_STATIC OR OGRE_STATIC) - pkg_message(OGRE "Build type (static, dynamic) does not match the requested one.") - set(OGRE_INCOMPATIBLE TRUE) - endif () - else () - pkg_message(OGRE "Could not determine Ogre build configuration.") - set(OGRE_INCOMPATIBLE TRUE) - endif () -else () - set(OGRE_INCOMPATIBLE FALSE) -endif () - -find_library(OGRE_LIBRARY_REL NAMES ${OGRE_LIBRARY_NAMES} HINTS ${OGRE_LIB_SEARCH_PATH} ${OGRE_PKGC_LIBRARY_DIRS} ${OGRE_FRAMEWORK_SEARCH_PATH} PATH_SUFFIXES "" "release" "relwithdebinfo" "minsizerel") -find_library(OGRE_LIBRARY_DBG NAMES ${OGRE_LIBRARY_NAMES_DBG} HINTS ${OGRE_LIB_SEARCH_PATH} ${OGRE_PKGC_LIBRARY_DIRS} ${OGRE_FRAMEWORK_SEARCH_PATH} PATH_SUFFIXES "" "debug") -make_library_set(OGRE_LIBRARY) - -if(APPLE) - set(OGRE_LIBRARY_DBG ${OGRE_LIB_SEARCH_PATH}) -endif() -if (OGRE_INCOMPATIBLE) - set(OGRE_LIBRARY "NOTFOUND") -endif () - -set(OGRE_INCLUDE_DIR ${OGRE_CONFIG_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}) -list(REMOVE_DUPLICATES OGRE_INCLUDE_DIR) -findpkg_finish(OGRE) -add_parent_dir(OGRE_INCLUDE_DIRS OGRE_INCLUDE_DIR) -if (OGRE_SOURCE) - # If working from source rather than SDK, add samples include - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} "${OGRE_SOURCE}/Samples/Common/include") -endif() - -mark_as_advanced(OGRE_CONFIG_INCLUDE_DIR OGRE_MEDIA_DIR OGRE_PLUGIN_DIR_REL OGRE_PLUGIN_DIR_DBG) - -if (NOT OGRE_FOUND) - return() -endif () - - -# look for required Ogre dependencies in case of static build and/or threading -if (OGRE_STATIC) - set(OGRE_DEPS_FOUND TRUE) - find_package(Cg QUIET) - find_package(DirectX QUIET) - find_package(FreeImage QUIET) - find_package(Freetype QUIET) - find_package(OpenGL QUIET) - find_package(OpenGLES QUIET) - find_package(OpenGLES2 QUIET) - find_package(ZLIB QUIET) - find_package(ZZip QUIET) - if (UNIX AND NOT APPLE AND NOT ANDROID) - find_package(X11 QUIET) - find_library(XAW_LIBRARY NAMES Xaw Xaw7 PATHS ${DEP_LIB_SEARCH_DIR} ${X11_LIB_SEARCH_PATH}) - if (NOT XAW_LIBRARY OR NOT X11_Xt_FOUND) - set(X11_FOUND FALSE) - endif () - endif () - if (APPLE AND NOT OGRE_BUILD_PLATFORM_APPLE_IOS) - find_package(Cocoa QUIET) - find_package(Carbon QUIET) - find_package(CoreVideo QUIET) - if (NOT Cocoa_FOUND OR NOT Carbon_FOUND OR NOT CoreVideo_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - if (APPLE AND OGRE_BUILD_PLATFORM_APPLE_IOS) - find_package(iOSSDK QUIET) - if (NOT iOSSDK_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${ZZip_LIBRARIES} ${ZLIB_LIBRARIES} ${FreeImage_LIBRARIES} ${FREETYPE_LIBRARIES} ) - - if (APPLE AND NOT OGRE_BUILD_PLATFORM_APPLE_IOS AND NOT ANDROID) - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${X11_LIBRARIES} ${X11_Xt_LIBRARIES} ${XAW_LIBRARY} ${X11_Xrandr_LIB} ${Carbon_LIBRARIES} ${Cocoa_LIBRARIES}) - endif() - - if (NOT ZLIB_FOUND OR NOT ZZip_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (NOT FreeImage_FOUND AND NOT OGRE_CONFIG_FREEIMAGE) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (NOT FREETYPE_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - if (UNIX AND NOT APPLE AND NOT ANDROID) - if (NOT X11_FOUND) - set(OGRE_DEPS_FOUND FALSE) - endif () - endif () - - if (OGRE_CONFIG_THREADS) - if (OGRE_CONFIG_THREAD_PROVIDER EQUAL 1) - find_package(Boost COMPONENTS thread QUIET) - if (NOT Boost_THREAD_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${Boost_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) - endif () - elseif (OGRE_CONFIG_THREAD_PROVIDER EQUAL 2) - find_package(POCO QUIET) - if (NOT POCO_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${POCO_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${POCO_INCLUDE_DIRS}) - endif () - elseif (OGRE_CONFIG_THREAD_PROVIDER EQUAL 3) - find_package(TBB QUIET) - if (NOT TBB_FOUND) - set(OGRE_DEPS_FOUND FALSE) - else () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${TBB_LIBRARIES}) - set(OGRE_INCLUDE_DIRS ${OGRE_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS}) - endif () - endif () - endif () - - if (NOT OGRE_DEPS_FOUND) - pkg_message(OGRE "Could not find all required dependencies for the Ogre package.") - set(OGRE_FOUND FALSE) - endif () -endif () - -if (NOT OGRE_FOUND) - return() -endif () - - -get_filename_component(OGRE_LIBRARY_DIR_REL "${OGRE_LIBRARY_REL}" PATH) -get_filename_component(OGRE_LIBRARY_DIR_DBG "${OGRE_LIBRARY_DBG}" PATH) -set(OGRE_LIBRARY_DIRS ${OGRE_LIBRARY_DIR_REL} ${OGRE_LIBRARY_DIR_DBG}) - -# find binaries -if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_BINARY_REL NAMES "OgreMain.dll" HINTS ${OGRE_BIN_SEARCH_PATH} - PATH_SUFFIXES "" release relwithdebinfo minsizerel) - find_file(OGRE_BINARY_DBG NAMES "OgreMain_d.dll" HINTS ${OGRE_BIN_SEARCH_PATH} - PATH_SUFFIXES "" debug ) - endif() - mark_as_advanced(OGRE_BINARY_REL OGRE_BINARY_DBG) -endif() - - -######################################################### -# Find Ogre components -######################################################### - -set(OGRE_COMPONENT_SEARCH_PATH_REL - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_BIN_SEARCH_PATH} -) -set(OGRE_COMPONENT_SEARCH_PATH_DBG - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_BIN_SEARCH_PATH} -) - -macro(ogre_find_component COMPONENT HEADER) - findpkg_begin(OGRE_${COMPONENT}) - find_path(OGRE_${COMPONENT}_INCLUDE_DIR NAMES ${HEADER} HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE} PATH_SUFFIXES ${COMPONENT} OGRE/${COMPONENT} Components/${COMPONENT}/include) - set(OGRE_${COMPONENT}_LIBRARY_NAMES "Ogre${COMPONENT}${OGRE_LIB_SUFFIX}") - get_debug_names(OGRE_${COMPONENT}_LIBRARY_NAMES) - find_library(OGRE_${COMPONENT}_LIBRARY_REL NAMES ${OGRE_${COMPONENT}_LIBRARY_NAMES} HINTS ${OGRE_LIBRARY_DIR_REL} PATH_SUFFIXES "" "release" "relwithdebinfo" "minsizerel") - find_library(OGRE_${COMPONENT}_LIBRARY_DBG NAMES ${OGRE_${COMPONENT}_LIBRARY_NAMES_DBG} HINTS ${OGRE_LIBRARY_DIR_DBG} PATH_SUFFIXES "" "debug") - make_library_set(OGRE_${COMPONENT}_LIBRARY) - findpkg_finish(OGRE_${COMPONENT}) - if (OGRE_${COMPONENT}_FOUND) - # find binaries - if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_${COMPONENT}_BINARY_REL NAMES "Ogre${COMPONENT}.dll" HINTS ${OGRE_COMPONENT_SEARCH_PATH_REL} PATH_SUFFIXES "" bin bin/release bin/relwithdebinfo bin/minsizerel release) - find_file(OGRE_${COMPONENT}_BINARY_DBG NAMES "Ogre${COMPONENT}_d.dll" HINTS ${OGRE_COMPONENT_SEARCH_PATH_DBG} PATH_SUFFIXES "" bin bin/debug debug) - endif() - mark_as_advanced(OGRE_${COMPONENT}_BINARY_REL OGRE_${COMPONENT}_BINARY_DBG) - endif() - endif() -endmacro() - -# look for Paging component -ogre_find_component(Paging OgrePaging.h) -# look for Terrain component -ogre_find_component(Terrain OgreTerrain.h) -# look for Property component -ogre_find_component(Property OgreProperty.h) -# look for RTShaderSystem component -ogre_find_component(RTShaderSystem OgreRTShaderSystem.h) - - -######################################################### -# Find Ogre plugins -######################################################### - -macro(ogre_find_plugin PLUGIN HEADER) - # On Unix, the plugins might have no prefix - if (CMAKE_FIND_LIBRARY_PREFIXES) - set(TMP_CMAKE_LIB_PREFIX ${CMAKE_FIND_LIBRARY_PREFIXES}) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "") - endif() - - # strip RenderSystem_ or Plugin_ prefix from plugin name - string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) - string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) - - # header files for plugins are not usually needed, but find them anyway if they are present - set(OGRE_PLUGIN_PATH_SUFFIXES - PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN} - RenderSystems RenderSystems/${PLUGIN_NAME} ${ARGN}) - find_path(OGRE_${PLUGIN}_INCLUDE_DIR NAMES ${HEADER} - HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE} - PATH_SUFFIXES ${OGRE_PLUGIN_PATH_SUFFIXES}) - # find link libraries for plugins - set(OGRE_${PLUGIN}_LIBRARY_NAMES "${PLUGIN}${OGRE_LIB_SUFFIX}") - get_debug_names(OGRE_${PLUGIN}_LIBRARY_NAMES) - set(OGRE_${PLUGIN}_LIBRARY_FWK ${OGRE_LIBRARY_FWK}) - find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) - find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt debug debug/opt) - make_library_set(OGRE_${PLUGIN}_LIBRARY) - - if (OGRE_${PLUGIN}_LIBRARY OR OGRE_${PLUGIN}_INCLUDE_DIR) - set(OGRE_${PLUGIN}_FOUND TRUE) - if (OGRE_${PLUGIN}_INCLUDE_DIR) - set(OGRE_${PLUGIN}_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIR}) - endif() - set(OGRE_${PLUGIN}_LIBRARIES ${OGRE_${PLUGIN}_LIBRARY}) - endif () - - mark_as_advanced(OGRE_${PLUGIN}_INCLUDE_DIR OGRE_${PLUGIN}_LIBRARY_REL OGRE_${PLUGIN}_LIBRARY_DBG OGRE_${PLUGIN}_LIBRARY_FWK) - - # look for plugin dirs - if (OGRE_${PLUGIN}_FOUND) - if (NOT OGRE_PLUGIN_DIR_REL OR NOT OGRE_PLUGIN_DIR_DBG) - if (WIN32) - set(OGRE_PLUGIN_SEARCH_PATH_REL - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_BIN_SEARCH_PATH} - ) - set(OGRE_PLUGIN_SEARCH_PATH_DBG - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_BIN_SEARCH_PATH} - ) - find_path(OGRE_PLUGIN_DIR_REL NAMES "${PLUGIN}.dll" HINTS ${OGRE_PLUGIN_SEARCH_PATH_REL} - PATH_SUFFIXES "" bin bin/release bin/relwithdebinfo bin/minsizerel release) - find_path(OGRE_PLUGIN_DIR_DBG NAMES "${PLUGIN}_d.dll" HINTS ${OGRE_PLUGIN_SEARCH_PATH_DBG} - PATH_SUFFIXES "" bin bin/debug debug) - elseif (UNIX) - get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_REL} PATH) - set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (release)") - get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_DBG} PATH) - set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)") - endif () - endif () - - # find binaries - if (NOT OGRE_STATIC) - if (WIN32) - find_file(OGRE_${PLUGIN}_REL NAMES "${PLUGIN}.dll" HINTS ${OGRE_PLUGIN_DIR_REL}) - find_file(OGRE_${PLUGIN}_DBG NAMES "${PLUGIN}_d.dll" HINTS ${OGRE_PLUGIN_DIR_DBG}) - endif() - mark_as_advanced(OGRE_${PLUGIN}_REL OGRE_${PLUGIN}_DBG) - endif() - - endif () - - if (TMP_CMAKE_LIB_PREFIX) - set(CMAKE_FIND_LIBRARY_PREFIXES ${TMP_CMAKE_LIB_PREFIX}) - endif () -endmacro(ogre_find_plugin) - -ogre_find_plugin(Plugin_PCZSceneManager OgrePCZSceneManager.h PCZ PlugIns/PCZSceneManager/include) -ogre_find_plugin(Plugin_OctreeZone OgreOctreeZone.h PCZ PlugIns/OctreeZone/include) -ogre_find_plugin(Plugin_BSPSceneManager OgreBspSceneManager.h PlugIns/BSPSceneManager/include) -ogre_find_plugin(Plugin_CgProgramManager OgreCgProgram.h PlugIns/CgProgramManager/include) -ogre_find_plugin(Plugin_OctreeSceneManager OgreOctreeSceneManager.h PlugIns/OctreeSceneManager/include) -ogre_find_plugin(Plugin_ParticleFX OgreParticleFXPrerequisites.h PlugIns/ParticleFX/include) -ogre_find_plugin(RenderSystem_GL OgreGLRenderSystem.h RenderSystems/GL/include) -ogre_find_plugin(RenderSystem_GLES OgreGLESRenderSystem.h RenderSystems/GLES/include) -ogre_find_plugin(RenderSystem_GLES2 OgreGLES2RenderSystem.h RenderSystems/GLES2/include) -ogre_find_plugin(RenderSystem_Direct3D9 OgreD3D9RenderSystem.h RenderSystems/Direct3D9/include) -ogre_find_plugin(RenderSystem_Direct3D11 OgreD3D11RenderSystem.h RenderSystems/Direct3D11/include) - -if (OGRE_STATIC) - # check if dependencies for plugins are met - if (NOT DirectX_FOUND) - set(OGRE_RenderSystem_Direct3D9_FOUND FALSE) - endif () - if (NOT DirectX_D3D11_FOUND) - set(OGRE_RenderSystem_Direct3D11_FOUND FALSE) - endif () - if (NOT OPENGL_FOUND) - set(OGRE_RenderSystem_GL_FOUND FALSE) - endif () - if (NOT OPENGLES_FOUND) - set(OGRE_RenderSystem_GLES_FOUND FALSE) - endif () - if (NOT OPENGLES2_FOUND) - set(OGRE_RenderSystem_GLES2_FOUND FALSE) - endif () - if (NOT Cg_FOUND) - set(OGRE_Plugin_CgProgramManager_FOUND FALSE) - endif () - - set(OGRE_RenderSystem_Direct3D9_LIBRARIES ${OGRE_RenderSystem_Direct3D9_LIBRARIES} - ${DirectX_LIBRARIES} - ) - - set(OGRE_RenderSystem_Direct3D11_LIBRARIES ${OGRE_RenderSystem_Direct3D11_LIBRARIES} - ${DirectX_D3D11_LIBRARIES} - ) - set(OGRE_RenderSystem_GL_LIBRARIES ${OGRE_RenderSystem_GL_LIBRARIES} - ${OPENGL_LIBRARIES} - ) - set(OGRE_RenderSystem_GLES_LIBRARIES ${OGRE_RenderSystem_GLES_LIBRARIES} - ${OPENGLES_LIBRARIES} - ) - set(OGRE_RenderSystem_GLES2_LIBRARIES ${OGRE_RenderSystem_GLES2_LIBRARIES} - ${OPENGLES2_LIBRARIES} - ) - set(OGRE_Plugin_CgProgramManager_LIBRARIES ${OGRE_Plugin_CgProgramManager_LIBRARIES} - ${Cg_LIBRARIES} - ) -endif () - -# look for the media directory -set(OGRE_MEDIA_SEARCH_PATH - ${OGRE_SOURCE} - ${OGRE_LIBRARY_DIR_REL}/.. - ${OGRE_LIBRARY_DIR_DBG}/.. - ${OGRE_LIBRARY_DIR_REL}/../.. - ${OGRE_LIBRARY_DIR_DBG}/../.. - ${OGRE_PREFIX_SOURCE} -) -set(OGRE_MEDIA_SEARCH_SUFFIX - Samples/Media - Media - media - share/OGRE/media -) - -clear_if_changed(OGRE_PREFIX_WATCH OGRE_MEDIA_DIR) -find_path(OGRE_MEDIA_DIR NAMES packs/cubemapsJS.zip HINTS ${OGRE_MEDIA_SEARCH_PATH} - PATHS ${OGRE_PREFIX_PATH} PATH_SUFFIXES ${OGRE_MEDIA_SEARCH_SUFFIX}) - diff --git a/cmake_modules/FindOIS.cmake b/cmake_modules/FindOIS.cmake deleted file mode 100644 index edaf9220017..00000000000 --- a/cmake_modules/FindOIS.cmake +++ /dev/null @@ -1,65 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OIS -# Once done, this will define -# -# OIS_FOUND - system has OIS -# OIS_INCLUDE_DIRS - the OIS include directories -# OIS_LIBRARIES - link these to use OIS - -include(FindPkgMacros) -findpkg_begin(OIS) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(OIS_HOME) -getenv_path(OGRE_HOME) -getenv_path(OGRE_SOURCE) - -# construct search paths -set(OIS_PREFIX_PATH ${OIS_HOME} ${ENV_OIS_HOME} - ${OGRE_SOURCE}/iPhoneDependencies ${ENV_OGRE_SOURCE}/iPhoneDependencies - ${OGRE_SOURCE}/Dependencies ${ENV_OGRE_SOURCE}/Dependencies - ${OGRE_HOME} ${ENV_OGRE_HOME}) -create_search_paths(OIS) -# redo search if prefix path changed -clear_if_changed(OIS_PREFIX_PATH - OIS_LIBRARY_FWK - OIS_LIBRARY_REL - OIS_LIBRARY_DBG - OIS_INCLUDE_DIR -) - -set(OIS_LIBRARY_NAMES OIS) -get_debug_names(OIS_LIBRARY_NAMES) - -use_pkgconfig(OIS_PKGC OIS) - -# For OIS, prefer static library over framework (important when referencing OIS source build) -set(CMAKE_FIND_FRAMEWORK "LAST") - -findpkg_framework(OIS) -if (OIS_HOME) - # OIS uses the 'includes' path for its headers in the source release, not 'include' - set(OIS_INC_SEARCH_PATH ${OIS_INC_SEARCH_PATH} ${OIS_HOME}/includes) -endif() -if (APPLE AND OIS_HOME) - # OIS source build on Mac stores libs in a different location - # Also this is for static build - set(OIS_LIB_SEARCH_PATH ${OIS_LIB_SEARCH_PATH} ${OIS_HOME}/Mac/XCode-2.2/build) -endif() -find_path(OIS_INCLUDE_DIR NAMES OIS.h HINTS ${OIS_INC_SEARCH_PATH} ${OIS_PKGC_INCLUDE_DIRS} PATH_SUFFIXES OIS) -find_library(OIS_LIBRARY_REL NAMES ${OIS_LIBRARY_NAMES} HINTS ${OIS_LIB_SEARCH_PATH} ${OIS_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(OIS_LIBRARY_DBG NAMES ${OIS_LIBRARY_NAMES_DBG} HINTS ${OIS_LIB_SEARCH_PATH} ${OIS_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(OIS_LIBRARY) - -findpkg_finish(OIS) - -# Reset framework finding -set(CMAKE_FIND_FRAMEWORK "FIRST") diff --git a/cmake_modules/FindOgg.cmake b/cmake_modules/FindOgg.cmake deleted file mode 100644 index c275bb351ef..00000000000 --- a/cmake_modules/FindOgg.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# - Try to find Ogg -# Once done, this will define -# -# Ogg_FOUND - system has Ogg -# Ogg_INCLUDE_DIRS - the Ogg include directories -# Ogg_LIBRARIES - link these to use Ogg - -include(LibFindMacros) - -# Use pkg-config to get hints about paths -libfind_pkg_check_modules(Ogg_PKGCONF Ogg) - -# Include dir -find_path(Ogg_INCLUDE_DIR - NAMES ogg/ogg.h - PATHS ${Ogg_PKGCONF_INCLUDE_DIRS} ${OGG_ROOT}/include -) - -# Finally the library itself -find_library(Ogg_LIBRARY - NAMES ogg - PATHS ${Ogg_PKGCONF_LIBRARY_DIRS} ${OGG_ROOT}/lib -) - -# Set the include dir variables and the libraries and let libfind_process do the rest. -# NOTE: Singular variables for this library, plural for libraries this this lib depends on. -set(Ogg_PROCESS_INCLUDES Ogg_INCLUDE_DIR Ogg_INCLUDE_DIRS) -set(Ogg_PROCESS_LIBS Ogg_LIBRARY Ogg_LIBRARIES) -libfind_process(Ogg) diff --git a/cmake_modules/FindOgreFFMPEG.cmake b/cmake_modules/FindOgreFFMPEG.cmake deleted file mode 100644 index 873a51bb10c..00000000000 --- a/cmake_modules/FindOgreFFMPEG.cmake +++ /dev/null @@ -1,48 +0,0 @@ -# - Find Ogre FFMPEG -# -# OgreFFMPEG_FOUND - True if OgreFFMPEG found. -# OgreFFMPEG_INCLUDE_DIR - where to find videoplayer.hpp, etc. -# OgreFFMPEG_LIBRARIES - List of libraries when using OgreFFMPEG. -# - -SET( OgreFFMPEG_INCLUDE_SEARCH_DIR - ${MINGW_ENV}/install/include - ${MINGW_ENV}/install/include/ogre-ffmpeg - /usr/local/include - /usr/local/include/ogre-ffmpeg - /usr/include - /sw/include # Fink - /opt/local/include # DarwinPorts - /opt/csw/include # Blastwave - /opt/include - /usr/freeware/include - ) - -SET( OgreFFMPEG_LIBRARY_SEARCH_DIR - ${MINGW_ENV}/install/lib - ${MINGW_ENV}/install/lib/Debug - ${MINGW_ENV}/install/lib/Release - /usr/local/lib - /usr/lib - /sw/lib - /opt/local/lib - /opt/csw/lib - /opt/lib - /usr/freeware/lib64 - ) - - -FIND_PATH( OgreFFMPEG_INCLUDE_DIR "videoplayer.hpp" -PATHS ${OgreFFMPEG_INCLUDE_SEARCH_DIR}) - -FIND_LIBRARY( OgreFFMPEG_LIBRARIES -NAMES "libogre-ffmpeg-videoplayer.a" -PATHS ${OgreFFMPEG_LIBRARY_SEARCH_DIR}) - - -# handle the QUIETLY and REQUIRED arguments and set OgreFFMPEG_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE( "FindPackageHandleStandardArgs" ) -FIND_PACKAGE_HANDLE_STANDARD_ARGS( "OgreFFMPEG" DEFAULT_MSG OgreFFMPEG_INCLUDE_DIR OgreFFMPEG_LIBRARIES) - - diff --git a/cmake_modules/FindOpenAL.cmake b/cmake_modules/FindOpenAL.cmake deleted file mode 100644 index 7271065a387..00000000000 --- a/cmake_modules/FindOpenAL.cmake +++ /dev/null @@ -1,35 +0,0 @@ -# - Try to find OpenAL -# Once done, this will define -# -# OpenAL_FOUND - system has OpenAL -# OpenAL_INCLUDE_DIRS - the OpenAL include directories -# OpenAL_LIBRARIES - link these to use OpenAL - -if(NOT OPENAL_ROOT) - set(OPENAL_ROOT $ENV{OPENAL_ROOT}) -endif() - -include(LibFindMacros) - -# Use pkg-config to get hints about paths -libfind_pkg_check_modules(OpenAL_PKGCONF OpenAL) - -# Include dir -find_path(OpenAL_INCLUDE_DIR - NAMES al.h - PATHS ${OpenAL_PKGCONF_INCLUDE_DIRS} ${OPENAL_ROOT}/include - PATH_SUFFIXES AL -) - -# OpenAL library -find_library(OpenAL_LIBRARY - NAMES OpenAL al openal OpenAL32 - PATHS ${OpenAL_PKGCONF_LIBRARY_DIRS} ${OPENAL_ROOT}/lib -) - -# Set the include dir variables and the libraries and let libfind_process do the rest. -# NOTE: Singular variables for this library, plural for libraries this this lib depends on. -set(OpenAL_PROCESS_INCLUDES OpenAL_INCLUDE_DIR OpenAL_INCLUDE_DIRS) -set(OpenAL_PROCESS_LIBS OpenAL_LIBRARY OpenAL_LIBRARIES) -libfind_process(OpenAL) - diff --git a/cmake_modules/FindPackageHelper.cmake b/cmake_modules/FindPackageHelper.cmake deleted file mode 100644 index 435649d201b..00000000000 --- a/cmake_modules/FindPackageHelper.cmake +++ /dev/null @@ -1,309 +0,0 @@ -# Copyright (c) 2010 Xynilex Project -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# This macro uses the following variable for input: -# ${name}_HOME - hint for finding the path -# ${name}_INTERNAL_HOME - internal hint for finding path (this is used first) -# ${name}_FIND_REQUIRED - should we exit if it is not found -# ${name}_FIND_QUIETLY - disable status messages -# ${name}_INCLUDE_NAMES - files to look for in the include directory -# ${name}_LIBRARY_NAMES - libraries to look for in the library directory -# ${name}_PREFIX_PATH - directories to look in -# ${name}_INCLUDE_PATH_SUFFIXES - suffixes to look in -# ${name}_LIBRARY_PATH_SUFFIXES - suffixes to look in -# ${name}_ONLY_STATIC - only look for static libraries -# ${name}_ONLY_SHARED - only look for shared libraries -# ${name}_PARENTS - parent names (use these variables for HOME, INTERNAL_HOME, etc) -# -# Outputs the following -# ${name}_FOUND - true if package was found -# ${name}_INCLUDE_DIRS - include directories -# ${name}_LIBRARIES - libraries needed to link -# ${name}_SHARED_LIBRARIES - libraries that are shared -# ${name}_INCLUDES_FOUND - list of files specified in ${name}_INCLUDE_NAMES found -# ${name}_LIBRARIES_FOUND - list of libraries specified in ${name}_LIBRARY_NAMES found - -include(LibraryPathHints) - -macro(FindPackage name) - - set(EVN_${name}_HOME $ENV{${name}_HOME}) - - # Saves some typing - set(CUR_HOME ${${name}_HOME}) - set(CUR_ENV_HOME ${ENV_${name}_HOME}) - set(CUR_INTERNAL_HOME ${${name}_INTERNAL_HOME}) - set(CUR_FIND_REQUIRED ${${name}_FIND_REQUIRED}) - set(CUR_FIND_QUIETLY ${${name}_FIND_QUIETLY}) - set(CUR_INCLUDE_NAMES ${${name}_INCLUDE_NAMES}) - set(CUR_LIBRARY_NAMES ${${name}_LIBRARY_NAMES}) - set(CUR_PREFIX_PATH ${${name}_PREFIX_PATH}) - set(CUR_INCLUDE_PATH_SUFFIXES ${${name}_INCLUDE_PATH_SUFFIXES}) - set(CUR_LIBRARY_PATH_SUFFIXES ${${name}_LIBRARY_PATH_SUFFIXES}) - set(CUR_ONLY_STATIC ${${name}_ONLY_STATIC}) - set(CUR_ONLY_SHARED ${${name}_ONLY_SHARED}) - set(CUR_STATIC_PERFERRED ${${name}_STATIC_PERFERRED}) - set(CUR_SHARED_PERFERRED ${${name}_SHARED_PERFERRED}) - - foreach(parent ${${name}_PARENTS}) - if(${parent}_HOME) - set(CUR_HOME ${${parent}_HOME}) - endif() - if(ENV_${parent}_HOME) - set(CUR_ENV_HOME $ENV{${name}_HOME}) - endif() - if(${parent}_INTERNAL_HOME) - set(CUR_INTERNAL_HOME ${${parent}_INTERNAL_HOME}) - endif() - if(${parent}_FIND_QUIETLY) - set(CUR_FIND_QUIETLY ${${parent}_FIND_QUIETLY}) - endif() - if(${parent}_FIND_REQUIRED) - set(CUR_FIND_REQUIRED ${${parent}_FIND_REQUIRED}) - endif() - - set(CUR_PREFIX_PATH ${CUR_PREFIX_PATH} ${${parent}_PREFIX_PATH}) - set(CUR_INCLUDE_PATH_SUFFIXES ${CUR_INCLUDE_PATH_SUFFIXES} ${${parent}_INCLUDE_PATH_SUFFIXES}) - set(CUR_LIBRARY_PATH_SUFFIXES ${CUR_LIBRARY_PATH_SUFFIXES} ${${parent}_LIBRARY_PATH_SUFFIXES}) - endforeach() - - set(${name}_HOME ${CUR_HOME} CACHE PATH "${name} installation directory.") - - # Output status message - if(NOT CUR_FIND_QUIETLY) - message(STATUS "Check for library '${name}'") - endif() - - # If this package is already found, skip it - if(${name}_FOUND) - if(NOT CUR_FIND_QUIETLY) - message(STATUS "Check for library '${name}' -- found") - endif() - return() - endif() - - set(${name}_FOUND TRUE) # Found unless proven otherwise - - # Some hardcoded hints - GetLibraryPathHints(${name}) - - set(CUR_SEARCH_DIRS - "${CUR_INTERNAL_HOME}" - "${CUR_HOME}" - "${CUR_ENV_HOME}" - "${CUR_PREFIX_PATH}" - ${${name}_PATH_HINTS} - ) - set(CUR_INCLUDE_PATH_SUFFIXES ${CUR_INCLUDE_PATH_SUFFIXES} ${${name}_PATH_SUFFIX_HINTS}) - set(CUR_LIBRARY_PATH_SUFFIXES ${CUR_LIBRARY_PATH_SUFFIXES} ${${name}_PATH_SUFFIX_HINTS}) - - # Look through all the include names and see if they are available - set(CUR_INCLUDE_DIRS "") - set(CUR_INCLUDES_FOUND "") - - foreach(inc ${CUR_INCLUDE_NAMES}) - if(NOT CUR_FIND_QUIETLY) - message(STATUS " Check for ${inc}") - endif() - - # Try to find the path - find_path(${inc}_PATH - NAMES "${inc}" - PATHS ${CUR_SEARCH_DIRS} - PATH_SUFFIXES ${CUR_INCLUDE_PATH_SUFFIXES} - ) - - # If we can't find the path, end the search. - if(NOT ${inc}_PATH) - if(NOT CUR_FIND_QUIETLY) - message(STATUS " Check for ${inc} -- missing") - endif() - set(${name}_FOUND FALSE) - else() - if(NOT CUR_FIND_QUIETLY) - message(STATUS " Check for ${inc} -- found") - endif() - set(CUR_INCLUDE_DIRS ${CUR_INCLUDE_DIRS} ${${inc}_PATH}) - set(CUR_INCLUDES_FOUND ${CUR_INCLUDES_FOUND} ${inc}) - endif() - - # Cleanup - mark_as_advanced(${inc}_PATH) - endforeach() - - # Check all library names - set(CUR_LIBRARIES "") - set(CUR_SHARED_LIBRARIES "") - set(CUR_LIBRARIES_FOUND "") - - foreach(rawlib ${CUR_LIBRARY_NAMES}) - FindLibraryHelper(${name} ${rawlib} "${CUR_SEARCH_DIRS}") - set(libname LIB_${rawlib}) - - if(${libname}_FOUND) - set(CUR_LIBRARIES ${CUR_LIBRARIES} ${${libname}_PATH}) - set(CUR_LIBRARIES_FOUND ${rawlib}) - - if(${libname}_SHARED AND NOT MSYS) - set(CUR_SHARED_LIBRARIES ${CUR_SHARED_LIBRARIES} ${${libname}_PATH}) - endif() - else() - set(${name}_FOUND FALSE) - endif() - endforeach() - - if(${name}_FOUND) - if(NOT CUR_FIND_QUIETLY) - message(STATUS "Check for library '${name}' -- found") - endif() - foreach(parent ${${name}_PARENTS}) - set(${parent}_LIBRARIES ${${parent}_LIBRARIES} ${CUR_LIBRARIES}) - set(${parent}_SHARED_LIBRARIES ${${parent}_SHARED_LIBRARIES} ${CUR_SHARED_LIBRARIES}) - set(${parent}_INCLUDE_DIRS ${${parent}_INCLUDE_DIRS} ${CUR_INCLUDE_DIRS}) - endforeach() - else() - if(CUR_FIND_REQUIRED) - foreach(parent ${${name}_PARENTS}) - set(${parent}_FOUND FALSE) - endforeach() - endif() - endif() - - if(${name}_PARENTS) - mark_as_advanced(${name}_HOME) - endif() - - set(${name}_INCLUDE_DIRS ${CUR_INCLUDE_DIRS}) - set(${name}_LIBRARIES ${CUR_LIBRARIES}) - set(${name}_SHARED_LIBRARIES ${CUR_SHARED_LIBRARIES}) - set(${name}_INCLUDES_FOUND ${CUR_INCLUDES_FOUND}) - set(${name}_LIBRARIES_FOUND ${CUR_LIBRARIES_FOUND}) -endmacro() - -# Returns ${libname}_PATH (with libname.whatever in the path) -macro(FindLibraryHelper name rawlib CUR_SEARCH_DIRS) - set(shared_lib ${CMAKE_SHARED_LIBRARY_PREFIX}${rawlib}${CMAKE_SHARED_LIBRARY_SUFFIX}) - set(static_lib ${CMAKE_STATIC_LIBRARY_PREFIX}${rawlib}${CMAKE_STATIC_LIBRARY_SUFFIX}) - set(base_shared_lib ${rawlib}${CMAKE_SHARED_LIBRARY_SUFFIX}) - set(base_static_lib ${rawlib}${CMAKE_STATIC_LIBRARY_SUFFIX}) - - set(libname LIB_${rawlib}) - - if(CUR_ONLY_STATIC) - set(${libname}_NAME ${static_lib}) - else() - set(${libname}_NAME ${shared_lib}) - endif() - - if(NOT CUR_FIND_QUIETLY) - message(STATUS " Check for ${${libname}_NAME}") - endif() - - # Try to find the library - find_path(${libname}_STATIC_PATH - NAMES "${static_lib}" - PATHS ${CUR_SEARCH_DIRS} ${CMAKE_SYSTEM_LIBRARY_PATH} - PATH_SUFFIXES ${CUR_LIBRARY_PATH_SUFFIXES} - ) - - find_path(${libname}_BASE_STATIC_PATH - NAMES "${base_static_lib}" - PATHS ${CUR_SEARCH_DIRS} ${CMAKE_SYSTEM_LIBRARY_PATH} - PATH_SUFFIXES ${CUR_LIBRARY_PATH_SUFFIXES} - ) - - find_path(${libname}_SHARED_PATH - NAMES "${shared_lib}" - PATHS ${CUR_SEARCH_DIRS} ${CMAKE_SYSTEM_LIBRARY_PATH} - PATH_SUFFIXES ${CUR_LIBRARY_PATH_SUFFIXES} - ) - - find_path(${libname}_BASE_SHARED_PATH - NAMES "${base_shared_lib}" - PATHS ${CUR_SEARCH_DIRS} ${CMAKE_SYSTEM_LIBRARY_PATH} - PATH_SUFFIXES ${CUR_LIBRARY_PATH_SUFFIXES} - ) - - # Choose which one is the best - set(${libname}_PATH FALSE) - set(${libname}_SHARED TRUE) - - if(CUR_ONLY_STATIC) - if(${libname}_STATIC_PATH) - set(${libname}_PATH ${${libname}_STATIC_PATH}) - set(${libname}_NAME ${static_lib}) - set(${libname}_SHARED FALSE) - elseif(${libname}_BASE_STATIC_PATH) - set(${libname}_PATH ${${libname}_BASE_STATIC_PATH}) - set(${libname}_NAME ${base_static_lib}) - set(${libname}_SHARED FALSE) - endif() - elseif(CUR_ONLY_SHARED) - if(${libname}_SHARED_PATH) - set(${libname}_PATH ${${libname}_SHARED_PATH}) - set(${libname}_NAME ${shared_lib}) - elseif(${libname}_BASE_SHARED_PATH) - set(${libname}_PATH ${${libname}_BASE_SHARED_PATH}) - set(${libname}_NAME ${base_shared_lib}) - endif() - else() - # Choose whichever one we can find - if(${libname}_SHARED_PATH) - set(${libname}_PATH ${${libname}_SHARED_PATH}) - set(${libname}_NAME ${shared_lib}) - elseif(${libname}_BASE_SHARED_PATH) - set(${libname}_PATH ${${libname}_BASE_SHARED_PATH}) - set(${libname}_NAME ${base_shared_lib}) - elseif(${libname}_STATIC_PATH) - set(${libname}_PATH ${${libname}_STATIC_PATH}) - set(${libname}_NAME ${static_lib}) - set(${libname}_SHARED FALSE) - elseif(${libname}_BASE_STATIC_PATH) - set(${libname}_PATH ${${libname}_BASE_STATIC_PATH}) - set(${libname}_NAME ${base_static_lib}) - set(${libname}_SHARED FALSE) - else() - # Not found - endif() - endif() - - if(${libname}_PATH) - # Found - if(NOT CUR_FIND_QUIETLY) - message(STATUS " Check for ${${libname}_NAME} -- found") - endif() - - set(${libname}_PATH "${${libname}_PATH}/${${libname}_NAME}") - set(${libname}_FOUND TRUE) - else() - # Missing - if(NOT CUR_FIND_QUIETLY) - message(STATUS " Check for ${${libname}_NAME} -- missing") - endif() - - set(${libname}_FOUND FALSE) - endif() - - # Cleanup - mark_as_advanced(${libname}_STATIC_PATH) - mark_as_advanced(${libname}_BASE_STATIC_PATH) - mark_as_advanced(${libname}_SHARED_PATH) - mark_as_advanced(${libname}_BASE_SHARED_PATH) -endmacro() diff --git a/cmake_modules/FindPkgMacros.cmake b/cmake_modules/FindPkgMacros.cmake deleted file mode 100644 index a3d20b2a242..00000000000 --- a/cmake_modules/FindPkgMacros.cmake +++ /dev/null @@ -1,144 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -################################################################## -# Provides some common functionality for the FindPackage modules -################################################################## - -# Begin processing of package -macro(findpkg_begin PREFIX) -if (NOT ${PREFIX}_FIND_QUIETLY) -message(STATUS "Looking for ${PREFIX}...") -endif () -endmacro(findpkg_begin) - -# Display a status message unless FIND_QUIETLY is set -macro(pkg_message PREFIX) -if (NOT ${PREFIX}_FIND_QUIETLY) -message(STATUS ${ARGN}) -endif () -endmacro(pkg_message) - -# Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes -macro(getenv_path VAR) -set(ENV_${VAR} $ENV{${VAR}}) -# replace won't work if var is blank -if (ENV_${VAR}) -string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) -endif () -endmacro(getenv_path) - -# Construct search paths for includes and libraries from a PREFIX_PATH -macro(create_search_paths PREFIX) -foreach(dir ${${PREFIX}_PREFIX_PATH}) -set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH} -${dir}/include ${dir}/include/${PREFIX} ${dir}/Headers) -set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} -${dir}/lib ${dir}/lib/${PREFIX} ${dir}/Libs) -set(${PREFIX}_BIN_SEARCH_PATH ${${PREFIX}_BIN_SEARCH_PATH} -${dir}/bin) -endforeach(dir) -set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH}) -endmacro(create_search_paths) - -# clear cache variables if a certain variable changed -macro(clear_if_changed TESTVAR) -# test against internal check variable -if (NOT "${${TESTVAR}}" STREQUAL "${${TESTVAR}_INT_CHECK}") -message(STATUS "${TESTVAR} changed.") -foreach(var ${ARGN}) -set(${var} "NOTFOUND" CACHE STRING "x" FORCE) -endforeach(var) -endif () -set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE) -endmacro(clear_if_changed) - -# Try to get some hints from pkg-config, if available -macro(use_pkgconfig PREFIX PKGNAME) -find_package(PkgConfig) -if (PKG_CONFIG_FOUND) -pkg_check_modules(${PREFIX} ${PKGNAME}) -endif () -endmacro (use_pkgconfig) - -# Couple a set of release AND debug libraries (or frameworks) -macro(make_library_set PREFIX) -if (${PREFIX}_FWK) -set(${PREFIX} ${${PREFIX}_FWK}) -elseif (${PREFIX}_REL AND ${PREFIX}_DBG) -set(${PREFIX} optimized ${${PREFIX}_REL} debug ${${PREFIX}_DBG}) -elseif (${PREFIX}_REL) -set(${PREFIX} ${${PREFIX}_REL}) -elseif (${PREFIX}_DBG) -set(${PREFIX} ${${PREFIX}_DBG}) -endif () -endmacro(make_library_set) - -# Generate debug names from given release names -macro(get_debug_names PREFIX) -foreach(i ${${PREFIX}}) -set(${PREFIX}_DBG ${${PREFIX}_DBG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) -endforeach(i) -endmacro(get_debug_names) - -# Add the parent dir from DIR to VAR -macro(add_parent_dir VAR DIR) -get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE) -set(${VAR} ${${VAR}} ${${DIR}_TEMP}) -endmacro(add_parent_dir) - -# Do the final processing for the package find. -macro(findpkg_finish PREFIX) -# skip if already processed during this run -if (NOT ${PREFIX}_FOUND) -if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) -set(${PREFIX}_FOUND TRUE) -set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) -set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) -if (NOT ${PREFIX}_FIND_QUIETLY) -message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}") -endif () -else () -if (NOT ${PREFIX}_FIND_QUIETLY) -message(STATUS "Could not locate ${PREFIX}") -endif () -if (${PREFIX}_FIND_REQUIRED) -message(FATAL_ERROR "Required library ${PREFIX} not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake.") -endif () -endif () - -mark_as_advanced(${PREFIX}_INCLUDE_DIR ${PREFIX}_LIBRARY ${PREFIX}_LIBRARY_REL ${PREFIX}_LIBRARY_DBG ${PREFIX}_LIBRARY_FWK) -endif () -endmacro(findpkg_finish) - - -# Slightly customised framework finder -MACRO(findpkg_framework fwk) -IF(APPLE) -SET(${fwk}_FRAMEWORK_PATH -${${fwk}_FRAMEWORK_SEARCH_PATH} -${CMAKE_FRAMEWORK_PATH} -~/Library/Frameworks -/Library/Frameworks -/System/Library/Frameworks -/Network/Library/Frameworks -/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks/ -) -FOREACH(dir ${${fwk}_FRAMEWORK_PATH}) -SET(fwkpath ${dir}/${fwk}.framework) -IF(EXISTS ${fwkpath}) -SET(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES} -${fwkpath}/Headers ${fwkpath}/PrivateHeaders) -if (NOT ${fwk}_LIBRARY_FWK) -SET(${fwk}_LIBRARY_FWK "-framework ${fwk}") -endif () -ENDIF(EXISTS ${fwkpath}) -ENDFOREACH(dir) -ENDIF(APPLE) -ENDMACRO(findpkg_framework) \ No newline at end of file diff --git a/cmake_modules/FindTinyXML.cmake b/cmake_modules/FindTinyXML.cmake deleted file mode 100644 index 7950b1c6a2d..00000000000 --- a/cmake_modules/FindTinyXML.cmake +++ /dev/null @@ -1,56 +0,0 @@ -# - Find TinyXML -# Find the native TinyXML includes and library -# -# TINYXML_FOUND - True if TinyXML found. -# TINYXML_INCLUDE_DIR - where to find tinyxml.h, etc. -# TINYXML_LIBRARIES - List of libraries when using TinyXML. -# - -SET( TINYXML_INCLUDE_SEARCH_DIR - ${TINYXML_ROOT}/include - ${TINYXML_ROOT}/include/tinyxml - ${TINYXMLDIR}/include - ${TINYXMLDIR}/tinyxml/include - /usr/local/include - /usr/include - /sw/include # Fink - /opt/local/include # DarwinPorts - /opt/csw/include # Blastwave - /opt/include - /usr/freeware/include - ) - -SET( TINYXML_LIBRARY_SEARCH_DIR - ${CEGUIDIR}/lib - ${CEGUI_ROOT}/lib - ${CEGUIDIR} - /usr/local/lib - /usr/lib - /sw/lib - /opt/local/lib - /opt/csw/lib - /opt/lib - [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;CEGUI_ROOT]/lib - /usr/freeware/lib64 - ) - -IF( TINYXML_INCLUDE_DIR ) -# Already in cache, be silent -SET( TinyXML_FIND_QUIETLY TRUE ) -ENDIF( TINYXML_INCLUDE_DIR ) - -FIND_PATH( TINYXML_INCLUDE_DIR "tinyxml.h" -PATHS ${TINYXML_INCLUDE_SEARCH_DIR}) - -FIND_LIBRARY( TINYXML_LIBRARIES -NAMES "tinyxml" -PATHS ${TINYXML_LIBRARY_SEARCH_DIR}) - - -# handle the QUIETLY and REQUIRED arguments and set TINYXML_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE( "FindPackageHandleStandardArgs" ) -FIND_PACKAGE_HANDLE_STANDARD_ARGS( "TinyXML" DEFAULT_MSG TINYXML_INCLUDE_DIR TINYXML_LIBRARIES ) - -MARK_AS_ADVANCED( TINYXML_INCLUDE_DIR TINYXML_LIBRARIES ) - diff --git a/cmake_modules/FindVorbis.cmake b/cmake_modules/FindVorbis.cmake deleted file mode 100644 index 02fe93da3d1..00000000000 --- a/cmake_modules/FindVorbis.cmake +++ /dev/null @@ -1,36 +0,0 @@ -# - Try to find Vorbis -# Once done, this will define -# -# Vorbis_FOUND - system has Vorbis -# Vorbis_INCLUDE_DIRS - the Vorbis include directories -# Vorbis_LIBRARIES - link these to use Vorbis - -include(LibFindMacros) - -# Use pkg-config to get hints about paths -libfind_pkg_check_modules(Vorbis_PKGCONF Vorbis) - -# Include dir -find_path(Vorbis_INCLUDE_DIR - NAMES vorbisfile.h - PATHS ${Vorbis_PKGCONF_INCLUDE_DIRS} ${VORBIS_ROOT}/include - PATH_SUFFIXES vorbis -) - -# Vorbis library -find_library(Vorbis_LIBRARY - NAMES vorbis - PATHS ${Vorbis_PKGCONF_LIBRARY_DIRS} ${VORBIS_ROOT}/lib -) - -# Vorbis file library -find_library(VorbisFile_LIBRARY - NAMES vorbisfile - PATHS ${Vorbis_PKGCONF_LIBRARY_DIRS} ${VORBIS_ROOT}/lib -) - -# Set the include dir variables and the libraries and let libfind_process do the rest. -# NOTE: Singular variables for this library, plural for libraries this this lib depends on. -set(Vorbis_PROCESS_INCLUDES Vorbis_INCLUDE_DIR Vorbis_INCLUDE_DIRS) -set(Vorbis_PROCESS_LIBS Vorbis_LIBRARY VorbisFile_LIBRARY Vorbis_LIBRARIES) -libfind_process(Vorbis) diff --git a/cmake_modules/FindcAudio.cmake b/cmake_modules/FindcAudio.cmake deleted file mode 100644 index 08120bfd9a4..00000000000 --- a/cmake_modules/FindcAudio.cmake +++ /dev/null @@ -1,31 +0,0 @@ -# - Try to find cAudio -# Once done, this will define -# -# cAudio_FOUND - system has cAudio -# cAudio_INCLUDE_DIRS - the cAudio include directories -# cAudio_LIBRARIES - link these to use cAudio -# -# Accepted Inputs: -# Those defined in FindPackageHelper.cmake (use cAudio for ${name}) -include(FindPackageHelper) -set(cAudio_INCLUDE_NAMES - cAudio.h - ) - -set(cAudio_LIBRARY_NAMES - cAudio - ) - -set(cAudio_INCLUDE_PATH_SUFFIXES - include - cAudio - include/cAudio - ) - -set(cAudio_LIBRARY_PATH_SUFFIXES - bin/linux-x86 - ) - -set(cAudio_ONLY_SHARED TRUE) # Require shared linking - -FindPackage(cAudio) diff --git a/cmake_modules/FindirrKlang.cmake b/cmake_modules/FindirrKlang.cmake deleted file mode 100644 index 773e5007cb6..00000000000 --- a/cmake_modules/FindirrKlang.cmake +++ /dev/null @@ -1,84 +0,0 @@ -# - Try to find irrKlang -# Once done this will define -# -# IRRKLANG_FOUND - system has irrKlang -# IRRKLANG_INCLUDE_DIRS - the irrKlang include directory -# IRRKLANG_LIBRARIES - Link these to use irrKlang -# IRRKLANG_DEFINITIONS - Compiler switches required for using irrKlang -# -# Copyright (c) 2006 Andreas Schneider -# -# Redistribution and use is allowed according to the terms of the New -# BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. -# - - -if (IRRKLANG_LIBRARIES AND IRRKLANG_INCLUDE_DIRS) - # in cache already - set(IRRKLANG_FOUND TRUE) -else (IRRKLANG_LIBRARIES AND IRRKLANG_INCLUDE_DIRS) - - find_path(IRRKLANG_INCLUDE_DIR - NAMES - irrKlang.h - ) - - find_library(IRRKLANG_LIBRARY - NAMES - IrrKlang - ) - - find_library(IRRKLANG_BASIC_LIBRARY - NAMES - irrKlang.dll - ) - - find_library(IRRKLANG_ikpMP3_LIBRARY - NAMES - ikpMP3.dll - ) - - find_library(IRRKLANG_ikpFlac_LIBRARY - NAMES - ikpFlac.dll - ) - set(IRRKLANG_LIBRARIES_DLL - ${IRRKLANG_BASIC_LIBRARY}; - ${IRRKLANG_ikpMP3_LIBRARY}; - ${IRRKLANG_ikpFlac_LIBRARY} - ) - - if (IRRKLANG_LIBRARY) - set(IRRKLANG_FOUND TRUE) - endif (IRRKLANG_LIBRARY) - - set(IRRKLANG_INCLUDE_DIRS - ${IRRKLANG_INCLUDE_DIR} - ) - - if (IRRKLANG_FOUND) - set(IRRKLANG_LIBRARIES - ${IRRKLANG_LIBRARIES} - ${IRRKLANG_LIBRARY} - ) - endif (IRRKLANG_FOUND) - - if (IRRKLANG_INCLUDE_DIRS AND IRRKLANG_LIBRARIES) - set(IRRKLANG_FOUND TRUE) - endif (IRRKLANG_INCLUDE_DIRS AND IRRKLANG_LIBRARIES) - - if (IRRKLANG_FOUND) - if (NOT IRRKLANG_FIND_QUIETLY) - message(STATUS "Found irrKlang: ${IRRKLANG_LIBRARIES}") - endif (NOT IRRKLANG_FIND_QUIETLY) - else (IRRKLANG_FOUND) - if (IRRKLANG_FIND_REQUIRED) - message(FATAL_ERROR "Could not find irrKlang") - endif (IRRKLANG_FIND_REQUIRED) - endif (IRRKLANG_FOUND) - - # show the IRRKLANG_INCLUDE_DIRS and IRRKLANG_LIBRARIES variables only in the advanced view - mark_as_advanced(IRRKLANG_INCLUDE_DIRS IRRKLANG_LIBRARIES IRRKLANG_BASIC_LIBRARY IRRKLANG_ikpMP3_LIBRARY IRRKLANG_ikpFlac_LIBRARY IRRKLANG_LIBRARIES_DLL) - -endif (IRRKLANG_LIBRARIES AND IRRKLANG_INCLUDE_DIRS) diff --git a/cmake_modules/LibFindMacros.cmake b/cmake_modules/LibFindMacros.cmake deleted file mode 100644 index 5a93b348fe1..00000000000 --- a/cmake_modules/LibFindMacros.cmake +++ /dev/null @@ -1,112 +0,0 @@ -# Version 1.0 (2013-04-12) -# Public Domain, originally written by Lasse Kärkkäinen -# Published at http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries - -# If you improve the script, please modify the forementioned wiki page because -# I no longer maintain my scripts (hosted as static files at zi.fi). Feel free -# to remove this entire header if you use real version control instead. - -# Changelog: -# 2013-04-12 Added version number (1.0) and this header, no other changes -# 2009-10-08 Originally published - - -# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments -# used for the current package. For this to work, the first parameter must be the -# prefix of the current package, then the prefix of the new package etc, which are -# passed to find_package. -macro (libfind_package PREFIX) - set (LIBFIND_PACKAGE_ARGS ${ARGN}) - if (${PREFIX}_FIND_QUIETLY) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) - endif (${PREFIX}_FIND_QUIETLY) - if (${PREFIX}_FIND_REQUIRED) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) - endif (${PREFIX}_FIND_REQUIRED) - find_package(${LIBFIND_PACKAGE_ARGS}) -endmacro (libfind_package) - -# CMake developers made the UsePkgConfig system deprecated in the same release (2.6) -# where they added pkg_check_modules. Consequently I need to support both in my scripts -# to avoid those deprecated warnings. Here's a helper that does just that. -# Works identically to pkg_check_modules, except that no checks are needed prior to use. -macro (libfind_pkg_check_modules PREFIX PKGNAME) - if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - include(UsePkgConfig) - pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) - else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(${PREFIX} ${PKGNAME}) - endif (PKG_CONFIG_FOUND) - endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) -endmacro (libfind_pkg_check_modules) - -# Do the final processing once the paths have been detected. -# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain -# all the variables, each of which contain one include directory. -# Ditto for ${PREFIX}_PROCESS_LIBS and library files. -# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. -# Also handles errors in case library detection was required, etc. -macro (libfind_process PREFIX) - # Skip processing if already processed during this run - if (NOT ${PREFIX}_FOUND) - # Start with the assumption that the library was found - set (${PREFIX}_FOUND TRUE) - - # Process all includes and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_INCLUDES}) - if (${i}) - set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Process all libraries and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_LIBS}) - if (${i}) - set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Print message and/or exit on fatal error - if (${PREFIX}_FOUND) - if (NOT ${PREFIX}_FIND_QUIETLY) - message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") - endif (NOT ${PREFIX}_FIND_QUIETLY) - else (${PREFIX}_FOUND) - if (${PREFIX}_FIND_REQUIRED) - foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) - message("${i}=${${i}}") - endforeach (i) - message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") - endif (${PREFIX}_FIND_REQUIRED) - endif (${PREFIX}_FOUND) - endif (NOT ${PREFIX}_FOUND) -endmacro (libfind_process) - -macro(libfind_library PREFIX basename) - set(TMP "") - if(MSVC80) - set(TMP -vc80) - endif(MSVC80) - if(MSVC90) - set(TMP -vc90) - endif(MSVC90) - set(${PREFIX}_LIBNAMES ${basename}${TMP}) - if(${ARGC} GREATER 2) - set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) - string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) - set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) - endif(${ARGC} GREATER 2) - find_library(${PREFIX}_LIBRARY - NAMES ${${PREFIX}_LIBNAMES} - PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} - ) -endmacro(libfind_library) - diff --git a/cmake_modules/LibraryPathHints.cmake b/cmake_modules/LibraryPathHints.cmake deleted file mode 100644 index bda98e74ac2..00000000000 --- a/cmake_modules/LibraryPathHints.cmake +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2010 Xynilex Project -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -macro(GetLibraryPathHints name) - set(${name}_PATH_HINTS - "${MINGW_ENV}/${name}" - "~/${name}" - "/usr" - "/usr/lib" - "/usr/include" - "/usr/local" - "/usr/local/lib" - "/usr/local/include" - "${CMAKE_CURRENT_SOURCE_DIR}/Libs" - "${CMAKE_CURRENT_SOURCE_DIR}/Libs/${name}" - ) - - set(${name}_PATH_SUFFIX_HINTS - include - Include - includes - Includes - lib - Lib - libs - Libs - bin - Bin - ) -endmacro() diff --git a/cmake_modules/PreprocessorUtils.cmake b/cmake_modules/PreprocessorUtils.cmake deleted file mode 100644 index de09a56c5c9..00000000000 --- a/cmake_modules/PreprocessorUtils.cmake +++ /dev/null @@ -1,59 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -macro(get_preprocessor_entry CONTENTS KEYWORD VARIABLE) - string(REGEX MATCH - "# *define +${KEYWORD} +((\"([^\n]*)\")|([^ \n]*))" - PREPROC_TEMP_VAR - ${${CONTENTS}} - ) - if (CMAKE_MATCH_3) - set(${VARIABLE} ${CMAKE_MATCH_3}) - else () - set(${VARIABLE} ${CMAKE_MATCH_4}) - endif () -endmacro() - -macro(has_preprocessor_entry CONTENTS KEYWORD VARIABLE) - string(REGEX MATCH - "\n *# *define +(${KEYWORD})" - PREPROC_TEMP_VAR - ${${CONTENTS}} - ) - if (CMAKE_MATCH_1) - set(${VARIABLE} TRUE) - else () - set(${VARIABLE} FALSE) - endif () -endmacro() - -macro(replace_preprocessor_entry VARIABLE KEYWORD NEW_VALUE) - string(REGEX REPLACE - "(// *)?# *define +${KEYWORD} +[^ \n]*" - "#define ${KEYWORD} ${NEW_VALUE}" - ${VARIABLE}_TEMP - ${${VARIABLE}} - ) - set(${VARIABLE} ${${VARIABLE}_TEMP}) -endmacro() - -macro(set_preprocessor_entry VARIABLE KEYWORD ENABLE) - if (${ENABLE}) - set(TMP_REPLACE_STR "#define ${KEYWORD}") - else () - set(TMP_REPLACE_STR "// #define ${KEYWORD}") - endif () - string(REGEX REPLACE - "(// *)?# *define +${KEYWORD} *\n" - ${TMP_REPLACE_STR} - ${VARIABLE}_TEMP - ${${VARIABLE}} - ) - set(${VARIABLE} ${${VARIABLE}_TEMP}) -endmacro() diff --git a/cmake_modules/add_to_project.cmake b/cmake_modules/add_to_project.cmake deleted file mode 100644 index cd7fe11d42e..00000000000 --- a/cmake_modules/add_to_project.cmake +++ /dev/null @@ -1,57 +0,0 @@ - - -################################################################################ -# Add to source files -################################################################################ - -# Adds all arguments to the global SOURCE_FILES property. -# -# Usage: -# -# add_source_files(main.cpp class.cpp class.hpp) -# -function(add_sources) - # make absolute paths - set(ABSOLUTE_FILENAMES) - foreach(FILENAME IN LISTS ARGN) - get_filename_component(FILENAME "${FILENAME}" ABSOLUTE) - list(APPEND ABSOLUTE_FILENAMES "${FILENAME}") - endforeach() - # append to global list - set_property(GLOBAL APPEND PROPERTY SOURCE_FILES "${ABSOLUTE_FILENAMES}") -endfunction() - -# A bit of documentation for the SOURCE_FILES property -define_property(GLOBAL PROPERTY SOURCE_FILES - BRIEF_DOCS "List of source files" - FULL_DOCS "List of source files to be compiled in one library" -) - - -################################################################################ -# Add to test files -################################################################################ - -# Adds all arguments to the global TEST_SOURCE_FILES property. -# -# Usage: -# -# add_test_sources(test.cpp test_class.cpp) -# -function(add_test_sources) - # make absolute paths - set(ABSOLUTE_FILENAMES) - foreach(FILENAME IN LISTS ARGN) - get_filename_component(FILENAME "${FILENAME}" ABSOLUTE) - list(APPEND ABSOLUTE_FILENAMES "${FILENAME}") - endforeach() - # append to global list - set_property(GLOBAL APPEND PROPERTY TEST_SOURCE_FILES "${ABSOLUTE_FILENAMES}") -endfunction() - -# A bit of documentation for the TEST_SOURCE_FILES property -define_property(GLOBAL PROPERTY TEST_SOURCE_FILES - BRIEF_DOCS "List of test source files" - FULL_DOCS "List of test source files to be compiled." -) - diff --git a/cmake_modules/compiler_flags.cmake b/cmake_modules/compiler_flags.cmake deleted file mode 100644 index 8f845bf9346..00000000000 --- a/cmake_modules/compiler_flags.cmake +++ /dev/null @@ -1,53 +0,0 @@ -################################################################################ -# Join function to make a string out of the lists -################################################################################ - -function(join TARGET) - set(_list) - foreach(_element ${ARGN}) - set(_list "${_list} ${_element}") - endforeach() - string(STRIP ${_list} _list) - set(${TARGET} ${_list} PARENT_SCOPE) -endfunction() - - -################################################################################ -# GCC warning flags -################################################################################ - -if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - - join(WARNING_FLAGS - -Werror - -Wall - -Wextra - # Miscellaneous warnings: - -Wcast-align - -Wcast-qual - -Wdisabled-optimization - -Wfloat-equal - -Wformat=2 - -Winit-self - #-Winline # Generates many useless warnings about destructors - -Wlogical-op - -Wmissing-declarations - -Wmissing-include-dirs - -Wpointer-arith - -Wredundant-decls - -Wstrict-overflow=2 - -Wswitch-default - -Wswitch-enum - -Wundef - -Wunreachable-code - # C++ specific - -Wctor-dtor-privacy - #-Weffc++ # Annoying member initialization - -Wold-style-cast - -Woverloaded-virtual - -Wsign-promo - -Wstrict-null-sentinel - ) - -endif() - diff --git a/cmake_modules/findMyGUI.cmake b/cmake_modules/findMyGUI.cmake deleted file mode 100644 index 9fc1c3dce9d..00000000000 --- a/cmake_modules/findMyGUI.cmake +++ /dev/null @@ -1,146 +0,0 @@ -# - Find MyGUI includes and library -# -# This module defines -# MYGUI_INCLUDE_DIRS -# MYGUI_LIBRARIES, the libraries to link against to use MYGUI. -# MYGUI_LIB_DIR, the location of the libraries -# MYGUI_FOUND, If false, do not try to use MYGUI -# -# Copyright © 2007, Matt Williams -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. -CMAKE_POLICY(PUSH) -include(FindPkgMacros) - -# IF (MYGUI_LIBRARIES AND MYGUI_INCLUDE_DIRS) - # SET(MYGUI_FIND_QUIETLY TRUE) -# ENDIF (MYGUI_LIBRARIES AND MYGUI_INCLUDE_DIRS) - -IF (WIN32) #Windows - MESSAGE(STATUS "Looking for MyGUI") - SET(MYGUISDK $ENV{MYGUI_HOME}) - IF (MYGUISDK) - findpkg_begin("MYGUI") - MESSAGE(STATUS "Using MyGUI in MyGUI SDK") - STRING(REGEX REPLACE "[\\]" "/" MYGUISDK "${MYGUISDK}") - message("${MYGUISDK}") - - find_path(MYGUI_INCLUDE_DIRS - MyGUI.h - "${MYGUISDK}/MyGUIEngine/include" - NO_DEFAULT_PATH) - - find_path(MYGUI_PLATFORM_INCLUDE_DIRS - MyGUI_OgrePlatform.h - "${MYGUISDK}/Platforms/Ogre/OgrePlatform/include" - NO_DEFAULT_PATH) - - SET(MYGUI_LIB_DIR ${MYGUISDK}/lib ${MYGUISDK}/*/lib) - - find_library(MYGUI_LIBRARIES_REL - NAMES MyGUIEngine MyGUI.OgrePlatform - HINTS ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" release relwithdebinfo minsizerel) - - find_library(MYGUI_LIBRARIES_DBG - NAMES MyGUIEngine_d MyGUI.OgrePlatform_d - HINTS ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" debug) - - find_library(MYGUI_PLATFORM_LIBRARIES_REL - NAMES MyGUI.OgrePlatform - HINTS ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" release relwithdebinfo minsizerel) - - find_library(MYGUI_PLATFORM_LIBRARIES_DBG - NAMES MyGUI.OgrePlatform_d - HINTS ${MYGUI_LIB_DIR} - PATH_SUFFIXES "" debug) - - ## Following needs equivelant section for Unix - find_library(MYGUI_LIBRARIES_FREETYPE - NAMES freetype - HINTS "$ENV{OGRE_DEPENDENCIES_DIR}/lib" - PATH_SUFFIXES "" Release relwithdebinfo minsizerel) - - # find_library(MYGUI_FREETYPE_LIBRARIES_DBG - # NAMES freetype_d - # HINTS "$ENV{OGRE_DEPENDENCIES_DIR}/lib" - # PATH_SUFFIXES "" Debug) - ## - - make_library_set(MYGUI_LIBRARIES) - make_library_set(MYGUI_PLATFORM_LIBRARIES) - - MESSAGE("${MYGUI_LIBRARIES}") - MESSAGE("${MYGUI_PLATFORM_LIBRARIES}") - ENDIF (MYGUISDK) - IF (OGRESOURCE) - MESSAGE(STATUS "Using MyGUI in OGRE dependencies") - STRING(REGEX REPLACE "[\\]" "/" OGRESDK "${OGRESOURCE}" ) - SET(MYGUI_INCLUDE_DIRS ${OGRESOURCE}/OgreMain/include/MYGUI) - SET(MYGUI_LIB_DIR ${OGRESOURCE}/lib) - SET(MYGUI_LIBRARIES debug Debug/MyGUIEngine_d optimized Release/MyGUIEngine) - ENDIF (OGRESOURCE) -ELSE (WIN32) #Unix - CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR) - FIND_PACKAGE(PkgConfig) - IF(MYGUI_STATIC) - IF (NOT APPLE) - PKG_SEARCH_MODULE(MYGUI MYGUIStatic MyGUIStatic) - IF (MYGUI_INCLUDE_DIRS) - SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) - SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) - SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - ELSE (MYGUI_INCLUDE_DIRS) - FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) - FIND_LIBRARY(MYGUI_LIBRARIES myguistatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) - STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") - STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") - ENDIF (MYGUI_INCLUDE_DIRS) - ELSE (NOT APPLE) - SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${MYGUI_DEPENDENCIES_DIR} ${OGRE_DEPENDENCIES_DIR}) - FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) - FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) - STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") - STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") - # freetype is needed on OS X for static builds - FIND_PACKAGE(freetype) - SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} ${FREETYPE_LIBRARIES}) - ENDIF (NOT APPLE) - ELSE(MYGUI_STATIC) - # Linux shared library - FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) - FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngine PATHS /usr/lib /usr/local/lib) - STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIBRARIES}") - ENDIF(MYGUI_STATIC) - - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") -ENDIF (WIN32) - -IF (MYGUI_INCLUDE_DIRS AND MYGUI_LIBRARIES) - SET(MYGUI_FOUND TRUE) -ENDIF() - -# We need explicit freetype libs only on OS X for static build -IF (NOT FREETYPE_LIBRARIES AND APPLE AND MYGUI_STATIC) - MESSAGE(FATAL_ERROR "Freetype is requires for static build on OS X") - SET(MYGUI_FOUND FALSE) -ENDIF() - -IF (MYGUI_FOUND) - MARK_AS_ADVANCED(MYGUI_LIB_DIR) - IF (NOT MYGUI_FIND_QUIETLY) - MESSAGE(STATUS " libraries : ${MYGUI_LIBRARIES} from ${MYGUI_LIB_DIR}") - MESSAGE(STATUS " includes : ${MYGUI_INCLUDE_DIRS}") - ENDIF (NOT MYGUI_FIND_QUIETLY) -ELSE (MYGUI_FOUND) - IF (MYGUI_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find MYGUI") - ENDIF (MYGUI_FIND_REQUIRED) -ENDIF (MYGUI_FOUND) - -CMAKE_POLICY(POP) diff --git a/cmake_modules/utils.cmake b/cmake_modules/utils.cmake deleted file mode 100644 index 2005407011f..00000000000 --- a/cmake_modules/utils.cmake +++ /dev/null @@ -1,56 +0,0 @@ - -function(SeparateLibrariesByBuildType LIB_LIST OUT_DEBUG OUT_RELEASE) - GetLibraryForBuildType( - "${LIB_LIST}" - "Release" - RELEASE_LIB - ) - set(${OUT_RELEASE} ${RELEASE_LIB} PARENT_SCOPE) - GetLibraryForBuildType( - "${LIB_LIST}" - "Debug" - DEBUG_LIB - ) - set(${OUT_DEBUG} ${DEBUG_LIB} PARENT_SCOPE) -endfunction() - - - -function(GetLibraryForBuildType LIB_LIST BUILD_TYPE OUT_LIB) - if(BUILD_TYPE STREQUAL "Debug") - list(FIND LIB_LIST "debug" LIB_INDEX_MINUS_ONE) - else() - list(FIND LIB_LIST "optimized" LIB_INDEX_MINUS_ONE) - endif() - if(LIB_INDEX_MINUS_ONE LESS 0) - set(${OUT_LIB} ${LIB_LIST} PARENT_SCOPE) - else() - math(EXPR LIB_INDEX "${LIB_INDEX_MINUS_ONE} + 1") - list(GET LIB_LIST ${LIB_INDEX} LIB_NAME) - set(${OUT_LIB} ${LIB_NAME} PARENT_SCOPE) - endif() -endfunction() - - -function(InstallFollowingSymlink FILE_LIST DESTINATION CONFIGURATIONS RENAME) - foreach(FILE_NAME ${FILE_LIST}) - get_filename_component(RESOLVED_FILE ${FILE_NAME} REALPATH) - if(EXISTS ${RESOLVED_FILE}) - if(RENAME) - get_filename_component(NAME ${FILE_NAME} NAME) - install(FILES - ${RESOLVED_FILE} - DESTINATION ${DESTINATION} - CONFIGURATIONS ${CONFIGURATIONS} - RENAME ${NAME} - ) - else() - install(FILES - ${RESOLVED_FILE} - DESTINATION ${DESTINATION} - CONFIGURATIONS ${CONFIGURATIONS} - ) - endif() - endif() - endforeach() -endfunction() diff --git a/contrib/googletest b/contrib/googletest deleted file mode 160000 index b3d0b4ea4ab..00000000000 --- a/contrib/googletest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b3d0b4ea4ab877a355e79dd0de704577811fff0f diff --git a/contrib/lua/building.txt b/contrib/lua/building.txt deleted file mode 100644 index 61c7dd79f54..00000000000 --- a/contrib/lua/building.txt +++ /dev/null @@ -1,6 +0,0 @@ -LuaJIT has a really complex makefile so go into the luajit/src folder -and run make - -Unfortunately there are some lua 5.2 features that need to be -explicitly enabled. So before running make uncomment this line in -`luajit/src/Makefile`: `#XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT` diff --git a/contrib/lua/luajit b/contrib/lua/luajit deleted file mode 160000 index b93a1dd0c83..00000000000 --- a/contrib/lua/luajit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b93a1dd0c831cab22f98163d0dde792a493c0eef diff --git a/contrib/lua/sol.hpp b/contrib/lua/sol.hpp deleted file mode 100755 index a39bf93ece8..00000000000 --- a/contrib/lua/sol.hpp +++ /dev/null @@ -1,14018 +0,0 @@ -// The MIT License (MIT) - -// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// This file was generated with a script. -// Generated 2017-04-25 23:43:53.892903 UTC -// This header was generated with sol v2.17.1 (revision 0db6d99) -// https://github.com/ThePhD/sol2 - -#ifndef SOL_SINGLE_INCLUDE_HPP -#define SOL_SINGLE_INCLUDE_HPP - -// beginning of sol.hpp - -#ifndef SOL_HPP -#define SOL_HPP - -#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER) -#define SOL_INSIDE_UNREAL -#endif // Unreal Engine 4 bullshit - -#ifdef SOL_INSIDE_UNREAL -#ifdef check -#define SOL_INSIDE_UNREAL_REMOVED_CHECK -#undef check -#endif -#endif // Unreal Engine 4 Bullshit - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" -#pragma GCC diagnostic ignored "-Wconversion" -#elif defined _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4324 ) // structure was padded due to alignment specifier -#endif // g++ - -// beginning of sol/state.hpp - -// beginning of sol/state_view.hpp - -// beginning of sol/error.hpp - -#include -#include - -namespace sol { - namespace detail { - struct direct_error_tag {}; - const auto direct_error = direct_error_tag{}; - } // detail - - class error : public std::runtime_error { - private: - // Because VC++ is a fuccboi - std::string w; - public: - error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {} - error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) {} - error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), w(str) {} - error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), w(std::move(str)) {} - - error(const error& e) = default; - error(error&& e) = default; - error& operator=(const error& e) = default; - error& operator=(error&& e) = default; - - virtual const char* what() const noexcept override { - return w.c_str(); - } - }; - -} // sol - -// end of sol/error.hpp - -// beginning of sol/table.hpp - -// beginning of sol/table_core.hpp - -// beginning of sol/proxy.hpp - -// beginning of sol/traits.hpp - -// beginning of sol/tuple.hpp - -#include -#include - -namespace sol { - namespace detail { - using swallow = std::initializer_list; - } // detail - - template - struct types { typedef std::make_index_sequence indices; static constexpr std::size_t size() { return sizeof...(Args); } }; - namespace meta { - namespace detail { - template - struct tuple_types_ { typedef types type; }; - - template - struct tuple_types_> { typedef types type; }; - } // detail - - template - using unqualified = std::remove_cv>; - - template - using unqualified_t = typename unqualified::type; - - template - using tuple_types = typename detail::tuple_types_::type; - - template - struct pop_front_type; - - template - using pop_front_type_t = typename pop_front_type::type; - - template - struct pop_front_type> { typedef void front_type; typedef types type; }; - - template - struct pop_front_type> { typedef Arg front_type; typedef types type; }; - - template - using tuple_element = std::tuple_element>; - - template - using tuple_element_t = std::tuple_element_t>; - - template - using unqualified_tuple_element = unqualified>; - - template - using unqualified_tuple_element_t = unqualified_t>; - - } // meta -} // sol - -// end of sol/tuple.hpp - -// beginning of sol/bind_traits.hpp - -namespace sol { - namespace meta { - namespace meta_detail { - - template - struct check_deducible_signature { - struct nat {}; - template - static auto test(int) -> decltype(&G::operator(), void()); - template - static auto test(...)->nat; - - using type = std::is_void(0))>; - }; - } // meta_detail - - template - struct has_deducible_signature : meta_detail::check_deducible_signature::type { }; - - namespace meta_detail { - - template - struct void_tuple_element : meta::tuple_element {}; - - template - struct void_tuple_element> { typedef void type; }; - - template - using void_tuple_element_t = typename void_tuple_element::type; - - template - struct basic_traits { - private: - typedef std::conditional_t::value, int, T>& first_type; - - public: - static const bool is_member_function = std::is_void::value; - static const bool has_c_var_arg = has_c_variadic; - static const std::size_t arity = sizeof...(Args); - static const std::size_t free_arity = sizeof...(Args)+static_cast(!std::is_void::value); - typedef types args_list; - typedef std::tuple args_tuple; - typedef T object_type; - typedef R return_type; - typedef tuple_types returns_list; - typedef R(function_type)(Args...); - typedef std::conditional_t::value, args_list, types> free_args_list; - typedef std::conditional_t::value, R(Args...), R(first_type, Args...)> free_function_type; - typedef std::conditional_t::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type; - typedef std::remove_pointer_t signature_type; - template - using arg_at = void_tuple_element_t; - }; - - template::value> - struct fx_traits : basic_traits {}; - - // Free Functions - template - struct fx_traits : basic_traits { - typedef R(*function_pointer_type)(Args...); - }; - - template - struct fx_traits : basic_traits { - typedef R(*function_pointer_type)(Args...); - }; - - template - struct fx_traits : basic_traits { - typedef R(*function_pointer_type)(Args..., ...); - }; - - template - struct fx_traits : basic_traits { - typedef R(*function_pointer_type)(Args..., ...); - }; - - // Member Functions - /* C-Style Variadics */ - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...); - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...); - }; - - /* Const Volatile */ - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) const; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) const; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) const volatile; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) const volatile; - }; - - /* Member Function Qualifiers */ - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) &; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) &; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) const &; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) const &; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) const volatile &; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) const volatile &; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) && ; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) && ; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) const &&; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) const &&; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args...) const volatile &&; - }; - - template - struct fx_traits : basic_traits { - typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&; - }; - - template - struct fx_traits : fx_traits::function_type, false> {}; - - template::value> - struct callable_traits : fx_traits> { - - }; - - template - struct callable_traits { - typedef R Arg; - typedef T object_type; - using signature_type = R(T::*); - static const bool is_member_function = false; - static const std::size_t arity = 1; - static const std::size_t free_arity = 2; - typedef std::tuple args_tuple; - typedef R return_type; - typedef types args_list; - typedef types free_args_list; - typedef meta::tuple_types returns_list; - typedef R(function_type)(T&, R); - typedef R(*function_pointer_type)(T&, R); - typedef R(*free_function_pointer_type)(T&, R); - template - using arg_at = void_tuple_element_t; - }; - } // meta_detail - - template - struct bind_traits : meta_detail::callable_traits {}; - - template - using function_args_t = typename bind_traits::args_list; - - template - using function_signature_t = typename bind_traits::signature_type; - - template - using function_return_t = typename bind_traits::return_type; - - } // meta -} // sol - -// end of sol/bind_traits.hpp - -#include -#include -#include - -namespace sol { - template - using index_value = std::integral_constant; - - namespace meta { - template - struct identity { typedef T type; }; - - template - using identity_t = typename identity::type; - - template - struct is_tuple : std::false_type { }; - - template - struct is_tuple> : std::true_type { }; - - template - struct is_builtin_type : std::integral_constant::value || std::is_pointer::value || std::is_array::value> {}; - - template - struct unwrapped { - typedef T type; - }; - - template - struct unwrapped> { - typedef T type; - }; - - template - using unwrapped_t = typename unwrapped::type; - - template - struct unwrap_unqualified : unwrapped> {}; - - template - using unwrap_unqualified_t = typename unwrap_unqualified::type; - - template - struct remove_member_pointer; - - template - struct remove_member_pointer { - typedef R type; - }; - - template - struct remove_member_pointer { - typedef R type; - }; - - template - using remove_member_pointer_t = remove_member_pointer; - - template class Templ, typename T> - struct is_specialization_of : std::false_type { }; - template class Templ> - struct is_specialization_of> : std::true_type { }; - - template - struct all_same : std::true_type { }; - - template - struct all_same : std::integral_constant ::value && all_same::value> { }; - - template - struct any_same : std::false_type { }; - - template - struct any_same : std::integral_constant ::value || any_same::value> { }; - - template - using invoke_t = typename T::type; - - template - using boolean = std::integral_constant; - - template - using neg = boolean; - - template - using condition = std::conditional_t; - - template - struct all : boolean {}; - - template - struct all : condition, boolean> {}; - - template - struct any : boolean {}; - - template - struct any : condition, any> {}; - - enum class enable_t { - _ - }; - - constexpr const auto enabler = enable_t::_; - - template - using disable_if_t = std::enable_if_t; - - template - using enable = std::enable_if_t::value, enable_t>; - - template - using disable = std::enable_if_t>::value, enable_t>; - - template - using disable_any = std::enable_if_t>::value, enable_t>; - - template - struct find_in_pack_v : boolean { }; - - template - struct find_in_pack_v : any, find_in_pack_v> { }; - - namespace meta_detail { - template - struct index_in_pack : std::integral_constant { }; - - template - struct index_in_pack : std::conditional_t::value, std::integral_constant, index_in_pack> { }; - } - - template - struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> { }; - - template - struct index_in : meta_detail::index_in_pack<0, T, List> { }; - - template - struct index_in> : meta_detail::index_in_pack<0, T, Args...> { }; - - template - struct at_in_pack {}; - - template - using at_in_pack_t = typename at_in_pack::type; - - template - struct at_in_pack : std::conditional> {}; - - template - struct at_in_pack<0, Arg, Args...> { typedef Arg type; }; - - namespace meta_detail { - template class Pred, typename... Ts> - struct count_for_pack : std::integral_constant {}; - template class Pred, typename T, typename... Ts> - struct count_for_pack : std::conditional_t < sizeof...(Ts) == 0 || Limit < 2, - std::integral_constant(Limit != 0 && Pred::value)>, - count_for_pack(Pred::value), Pred, Ts...> - > { }; - template class Pred, typename... Ts> - struct count_2_for_pack : std::integral_constant {}; - template class Pred, typename T, typename U, typename... Ts> - struct count_2_for_pack : std::conditional_t(Pred::value)>, - count_2_for_pack(Pred::value), Pred, Ts...> - > { }; - } // meta_detail - - template class Pred, typename... Ts> - struct count_for_pack : meta_detail::count_for_pack { }; - - template class Pred, typename List> - struct count_for; - - template class Pred, typename... Args> - struct count_for> : count_for_pack {}; - - template class Pred, typename... Ts> - struct count_for_to_pack : meta_detail::count_for_pack { }; - - template class Pred, typename... Ts> - struct count_2_for_pack : meta_detail::count_2_for_pack<0, Pred, Ts...> { }; - - template - struct return_type { - typedef std::tuple type; - }; - - template - struct return_type { - typedef T type; - }; - - template<> - struct return_type<> { - typedef void type; - }; - - template - using return_type_t = typename return_type::type; - - namespace meta_detail { - template struct always_true : std::true_type {}; - struct is_invokable_tester { - template - always_true()(std::declval()...))> static test(int); - template - std::false_type static test(...); - }; - } // meta_detail - - template - struct is_invokable; - template - struct is_invokable : decltype(meta_detail::is_invokable_tester::test(0)) {}; - - namespace meta_detail { - - template>::value> - struct is_callable : std::is_function> {}; - - template - struct is_callable { - using yes = char; - using no = struct { char s[2]; }; - - struct F { void operator()(); }; - struct Derived : T, F {}; - template struct Check; - - template - static no test(Check*); - - template - static yes test(...); - - static const bool value = sizeof(test(0)) == sizeof(yes); - }; - - struct has_begin_end_impl { - template, - typename B = decltype(std::declval().begin()), - typename E = decltype(std::declval().end())> - static std::true_type test(int); - - template - static std::false_type test(...); - }; - - struct has_key_value_pair_impl { - template, - typename V = typename U::value_type, - typename F = decltype(std::declval().first), - typename S = decltype(std::declval().second)> - static std::true_type test(int); - - template - static std::false_type test(...); - }; - - template () < std::declval())> - std::true_type supports_op_less_test(const T&); - std::false_type supports_op_less_test(...); - template () == std::declval())> - std::true_type supports_op_equal_test(const T&); - std::false_type supports_op_equal_test(...); - template () <= std::declval())> - std::true_type supports_op_less_equal_test(const T&); - std::false_type supports_op_less_equal_test(...); - - } // meta_detail - - template - using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval())); - template - using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval())); - template - using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval())); - - template - struct is_callable : boolean::value> {}; - - template - struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test(0)) {}; - - template - struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test(0)) {}; - - template - using is_string_constructible = any, const char*>, std::is_same, char>, std::is_same, std::string>, std::is_same, std::initializer_list>>; - - template - using is_c_str = any< - std::is_same>, const char*>, - std::is_same>, char*>, - std::is_same, std::string> - >; - - template - struct is_move_only : all< - neg>, - neg>>, - std::is_move_constructible> - > {}; - - template - using is_not_move_only = neg>; - - namespace meta_detail { - template >> = meta::enabler> - decltype(auto) force_tuple(T&& x) { - return std::forward_as_tuple(std::forward(x)); - } - - template >> = meta::enabler> - decltype(auto) force_tuple(T&& x) { - return std::forward(x); - } - } // meta_detail - - template - decltype(auto) tuplefy(X&&... x) { - return std::tuple_cat(meta_detail::force_tuple(std::forward(x))...); - } - } // meta - namespace detail { - template - decltype(auto) forward_get(Tuple&& tuple) { - return std::forward>(std::get(tuple)); - } - - template - auto forward_tuple_impl(std::index_sequence, Tuple&& tuple) -> decltype(std::tuple(tuple))...>(forward_get(tuple)...)) { - return std::tuple(tuple))...>(std::move(std::get(tuple))...); - } - - template - auto forward_tuple(Tuple&& tuple) { - auto x = forward_tuple_impl(std::make_index_sequence>::value>(), std::forward(tuple)); - return x; - } - - template - auto unwrap(T&& item) -> decltype(std::forward(item)) { - return std::forward(item); - } - - template - T& unwrap(std::reference_wrapper arg) { - return arg.get(); - } - - template - auto deref(T&& item) -> decltype(std::forward(item)) { - return std::forward(item); - } - - template - inline T& deref(T* item) { - return *item; - } - - template - inline std::add_lvalue_reference_t deref(std::unique_ptr& item) { - return *item; - } - - template - inline std::add_lvalue_reference_t deref(std::shared_ptr& item) { - return *item; - } - - template - inline std::add_lvalue_reference_t deref(const std::unique_ptr& item) { - return *item; - } - - template - inline std::add_lvalue_reference_t deref(const std::shared_ptr& item) { - return *item; - } - - template - inline T* ptr(T& val) { - return std::addressof(val); - } - - template - inline T* ptr(std::reference_wrapper val) { - return std::addressof(val.get()); - } - - template - inline T* ptr(T* val) { - return val; - } - } // detail -} // sol - -// end of sol/traits.hpp - -// beginning of sol/object.hpp - -// beginning of sol/reference.hpp - -// beginning of sol/types.hpp - -// beginning of sol/optional.hpp - -// beginning of sol/compatibility.hpp - -// beginning of sol/compatibility/version.hpp - -#ifdef SOL_USING_CXX_LUA -#include -#include -#include -#else -#ifndef lua_h -#include -#endif -#endif // C++ Mangling for Lua - -#if defined(_WIN32) || defined(_MSC_VER) -#ifndef SOL_CODECVT_SUPPORT -#define SOL_CODECVT_SUPPORT 1 -#endif // sol codecvt support -#elif defined(__GNUC__) -#if __GNUC__ >= 5 -#ifndef SOL_CODECVT_SUPPORT -#define SOL_CODECVT_SUPPORT 1 -#endif // codecvt support -#endif // g++ 5.x.x (MinGW too) -#else -#endif // Windows/VC++ vs. g++ vs Others - -#ifdef LUAJIT_VERSION -#ifndef SOL_LUAJIT -#define SOL_LUAJIT -#define SOL_LUAJIT_VERSION LUAJIT_VERSION_NUM -#endif // sol luajit -#endif // luajit - -#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 -#define SOL_LUA_VERSION LUA_VERSION_NUM -#elif defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 -#define SOL_LUA_VERSION LUA_VERSION_NUM -#elif !defined(LUA_VERSION_NUM) -#define SOL_LUA_VERSION 500 -#else -#define SOL_LUA_VERSION 502 -#endif // Lua Version 502, 501 || luajit, 500 - -#ifdef _MSC_VER -#ifdef _DEBUG -#ifndef NDEBUG -#ifndef SOL_CHECK_ARGUMENTS -#endif // Check Arguments -#ifndef SOL_SAFE_USERTYPE -#define SOL_SAFE_USERTYPE -#endif // Safe Usertypes -#endif // NDEBUG -#endif // Debug - -#ifndef _CPPUNWIND -#ifndef SOL_NO_EXCEPTIONS -#define SOL_NO_EXCEPTIONS 1 -#endif -#endif // Automatic Exceptions - -#ifndef _CPPRTTI -#ifndef SOL_NO_RTTI -#define SOL_NO_RTTI 1 -#endif -#endif // Automatic RTTI - -#elif defined(__GNUC__) || defined(__clang__) - -#ifndef NDEBUG -#ifndef __OPTIMIZE__ -#ifndef SOL_CHECK_ARGUMENTS -#endif // Check Arguments -#ifndef SOL_SAFE_USERTYPE -#define SOL_SAFE_USERTYPE -#endif // Safe Usertypes -#endif // g++ optimizer flag -#endif // Not Debug - -#ifndef __EXCEPTIONS -#ifndef SOL_NO_EXCEPTIONS -#define SOL_NO_EXCEPTIONS 1 -#endif -#endif // No Exceptions - -#ifndef __GXX_RTTI -#ifndef SOL_NO_RTII -#define SOL_NO_RTTI 1 -#endif -#endif // No RTTI - -#endif // vc++ || clang++/g++ - -#ifndef SOL_SAFE_USERTYPE -#ifdef SOL_CHECK_ARGUMENTS -#define SOL_SAFE_USERTYPE -#endif // Turn on Safety for all -#endif // Safe Usertypes - -// end of sol/compatibility/version.hpp - -#ifndef SOL_NO_COMPAT - -#if defined(__cplusplus) && !defined(SOL_USING_CXX_LUA) -extern "C" { -#endif -// beginning of sol/compatibility/5.2.0.h - -#ifndef SOL_5_2_0_H -#define SOL_5_2_0_H - -#if SOL_LUA_VERSION < 503 - -inline int lua_isinteger(lua_State* L, int idx) { - if (lua_type(L, idx) != LUA_TNUMBER) - return 0; - // This is a very slipshod way to do the testing - // but lua_totingerx doesn't play ball nicely - // on older versions... - lua_Number n = lua_tonumber(L, idx); - lua_Integer i = lua_tointeger(L, idx); - if (i != n) - return 0; - // it's DEFINITELY an integer - return 1; -} - -#endif // SOL_LUA_VERSION == 502 -#endif // SOL_5_2_0_H -// end of sol/compatibility/5.2.0.h - -// beginning of sol/compatibility/5.1.0.h - -#ifndef SOL_5_1_0_H -#define SOL_5_1_0_H - -#if SOL_LUA_VERSION == 501 -/* Lua 5.1 */ - -#include -#include -#include - -/* LuaJIT doesn't define these unofficial macros ... */ -#if !defined(LUAI_INT32) -#include -#if INT_MAX-20 < 32760 -#define LUAI_INT32 long -#define LUAI_UINT32 unsigned long -#elif INT_MAX > 2147483640L -#define LUAI_INT32 int -#define LUAI_UINT32 unsigned int -#else -#error "could not detect suitable lua_Unsigned datatype" -#endif -#endif - -/* LuaJIT does not have the updated error codes for thread status/function returns */ -#ifndef LUA_ERRGCMM -#define LUA_ERRGCMM (LUA_ERRERR + 2) -#endif // LUA_ERRGCMM - -/* LuaJIT does not support continuation contexts / return error codes? */ -#ifndef LUA_KCONTEXT -#define LUA_KCONTEXT std::ptrdiff_t -typedef LUA_KCONTEXT lua_KContext; -typedef int(*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); -#endif // LUA_KCONTEXT - -#define LUA_OPADD 0 -#define LUA_OPSUB 1 -#define LUA_OPMUL 2 -#define LUA_OPDIV 3 -#define LUA_OPMOD 4 -#define LUA_OPPOW 5 -#define LUA_OPUNM 6 -#define LUA_OPEQ 0 -#define LUA_OPLT 1 -#define LUA_OPLE 2 - -typedef LUAI_UINT32 lua_Unsigned; - -typedef struct luaL_Buffer_52 { - luaL_Buffer b; /* make incorrect code crash! */ - char *ptr; - size_t nelems; - size_t capacity; - lua_State *L2; -} luaL_Buffer_52; -#define luaL_Buffer luaL_Buffer_52 - -#define lua_tounsigned(L, i) lua_tounsignedx(L, i, NULL) - -#define lua_rawlen(L, i) lua_objlen(L, i) - -inline void lua_callk(lua_State *L, int nargs, int nresults, lua_KContext, lua_KFunction) { - // should probably warn the user of Lua 5.1 that continuation isn't supported... - lua_call(L, nargs, nresults); -} -inline int lua_pcallk(lua_State *L, int nargs, int nresults, int errfunc, lua_KContext, lua_KFunction) { - // should probably warn the user of Lua 5.1 that continuation isn't supported... - return lua_pcall(L, nargs, nresults, errfunc); -} -void lua_arith(lua_State *L, int op); -int lua_compare(lua_State *L, int idx1, int idx2, int op); -void lua_pushunsigned(lua_State *L, lua_Unsigned n); -lua_Unsigned luaL_checkunsigned(lua_State *L, int i); -lua_Unsigned lua_tounsignedx(lua_State *L, int i, int *isnum); -lua_Unsigned luaL_optunsigned(lua_State *L, int i, lua_Unsigned def); -lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum); -void lua_len(lua_State *L, int i); -int luaL_len(lua_State *L, int i); -const char *luaL_tolstring(lua_State *L, int idx, size_t *len); -void luaL_requiref(lua_State *L, char const* modname, lua_CFunction openf, int glb); - -#define luaL_buffinit luaL_buffinit_52 -void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B); - -#define luaL_prepbuffsize luaL_prepbuffsize_52 -char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s); - -#define luaL_addlstring luaL_addlstring_52 -void luaL_addlstring(luaL_Buffer_52 *B, const char *s, size_t l); - -#define luaL_addvalue luaL_addvalue_52 -void luaL_addvalue(luaL_Buffer_52 *B); - -#define luaL_pushresult luaL_pushresult_52 -void luaL_pushresult(luaL_Buffer_52 *B); - -#undef luaL_buffinitsize -#define luaL_buffinitsize(L, B, s) \ - (luaL_buffinit(L, B), luaL_prepbuffsize(B, s)) - -#undef luaL_prepbuffer -#define luaL_prepbuffer(B) \ - luaL_prepbuffsize(B, LUAL_BUFFERSIZE) - -#undef luaL_addchar -#define luaL_addchar(B, c) \ - ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize(B, 1)), \ - ((B)->ptr[(B)->nelems++] = (c))) - -#undef luaL_addsize -#define luaL_addsize(B, s) \ - ((B)->nelems += (s)) - -#undef luaL_addstring -#define luaL_addstring(B, s) \ - luaL_addlstring(B, s, strlen(s)) - -#undef luaL_pushresultsize -#define luaL_pushresultsize(B, s) \ - (luaL_addsize(B, s), luaL_pushresult(B)) - -typedef struct kepler_lua_compat_get_string_view { - const char *s; - size_t size; -} kepler_lua_compat_get_string_view; - -inline const char* kepler_lua_compat_get_string(lua_State* L, void* ud, size_t* size) { - kepler_lua_compat_get_string_view* ls = (kepler_lua_compat_get_string_view*) ud; - (void)L; - if (ls->size == 0) return NULL; - *size = ls->size; - ls->size = 0; - return ls->s; -} - -#if !defined(SOL_LUAJIT) || (SOL_LUAJIT_VERSION < 20100) - -inline int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, const char* name, const char*) { - kepler_lua_compat_get_string_view ls; - ls.s = buff; - ls.size = size; - return lua_load(L, kepler_lua_compat_get_string, &ls, name/*, mode*/); -} - -#endif // LuaJIT 2.1.x beta and beyond - -#endif /* Lua 5.1 */ - -#endif // SOL_5_1_0_H -// end of sol/compatibility/5.1.0.h - -// beginning of sol/compatibility/5.0.0.h - -#ifndef SOL_5_0_0_H -#define SOL_5_0_0_H - -#if SOL_LUA_VERSION < 501 -/* Lua 5.0 */ - -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") - -#define luaL_Reg luaL_reg - -#define luaL_opt(L, f, n, d) \ - (lua_isnoneornil(L, n) ? (d) : f(L, n)) - -#define luaL_addchar(B,c) \ - ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ - (*(B)->p++ = (char)(c))) - -#endif // Lua 5.0 - -#endif // SOL_5_0_0_H -// end of sol/compatibility/5.0.0.h - -// beginning of sol/compatibility/5.x.x.h - -#ifndef SOL_5_X_X_H -#define SOL_5_X_X_H - -#if SOL_LUA_VERSION < 502 - -#define LUA_RIDX_GLOBALS LUA_GLOBALSINDEX - -#define LUA_OK 0 - -#define lua_pushglobaltable(L) \ - lua_pushvalue(L, LUA_GLOBALSINDEX) - -#define luaL_newlib(L, l) \ - (lua_newtable((L)),luaL_setfuncs((L), (l), 0)) - -void luaL_checkversion(lua_State *L); - -int lua_absindex(lua_State *L, int i); -void lua_copy(lua_State *L, int from, int to); -void lua_rawgetp(lua_State *L, int i, const void *p); -void lua_rawsetp(lua_State *L, int i, const void *p); -void *luaL_testudata(lua_State *L, int i, const char *tname); -lua_Number lua_tonumberx(lua_State *L, int i, int *isnum); -void lua_getuservalue(lua_State *L, int i); -void lua_setuservalue(lua_State *L, int i); -void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup); -void luaL_setmetatable(lua_State *L, const char *tname); -int luaL_getsubtable(lua_State *L, int i, const char *name); -void luaL_traceback(lua_State *L, lua_State *L1, const char *msg, int level); -int luaL_fileresult(lua_State *L, int stat, const char *fname); - -#endif // Lua 5.1 and below - -#endif // SOL_5_X_X_H -// end of sol/compatibility/5.x.x.h - -// beginning of sol/compatibility/5.x.x.inl - -#ifndef SOL_5_X_X_INL -#define SOL_5_X_X_INL - -#if SOL_LUA_VERSION < 502 - -#include - -#define PACKAGE_KEY "_sol.package" - -inline int lua_absindex(lua_State *L, int i) { - if (i < 0 && i > LUA_REGISTRYINDEX) - i += lua_gettop(L) + 1; - return i; -} - -inline void lua_copy(lua_State *L, int from, int to) { - int abs_to = lua_absindex(L, to); - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushvalue(L, from); - lua_replace(L, abs_to); -} - -inline void lua_rawgetp(lua_State *L, int i, const void *p) { - int abs_i = lua_absindex(L, i); - lua_pushlightuserdata(L, (void*)p); - lua_rawget(L, abs_i); -} - -inline void lua_rawsetp(lua_State *L, int i, const void *p) { - int abs_i = lua_absindex(L, i); - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushlightuserdata(L, (void*)p); - lua_insert(L, -2); - lua_rawset(L, abs_i); -} - -inline void *luaL_testudata(lua_State *L, int i, const char *tname) { - void *p = lua_touserdata(L, i); - luaL_checkstack(L, 2, "not enough stack slots"); - if (p == NULL || !lua_getmetatable(L, i)) - return NULL; - else { - int res = 0; - luaL_getmetatable(L, tname); - res = lua_rawequal(L, -1, -2); - lua_pop(L, 2); - if (!res) - p = NULL; - } - return p; -} - -inline lua_Number lua_tonumberx(lua_State *L, int i, int *isnum) { - lua_Number n = lua_tonumber(L, i); - if (isnum != NULL) { - *isnum = (n != 0 || lua_isnumber(L, i)); - } - return n; -} - -inline static void push_package_table(lua_State *L) { - lua_pushliteral(L, PACKAGE_KEY); - lua_rawget(L, LUA_REGISTRYINDEX); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - /* try to get package table from globals */ - lua_pushliteral(L, "package"); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_istable(L, -1)) { - lua_pushliteral(L, PACKAGE_KEY); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); - } - } -} - -inline void lua_getuservalue(lua_State *L, int i) { - luaL_checktype(L, i, LUA_TUSERDATA); - luaL_checkstack(L, 2, "not enough stack slots"); - lua_getfenv(L, i); - lua_pushvalue(L, LUA_GLOBALSINDEX); - if (lua_rawequal(L, -1, -2)) { - lua_pop(L, 1); - lua_pushnil(L); - lua_replace(L, -2); - } - else { - lua_pop(L, 1); - push_package_table(L); - if (lua_rawequal(L, -1, -2)) { - lua_pop(L, 1); - lua_pushnil(L); - lua_replace(L, -2); - } - else - lua_pop(L, 1); - } -} - -inline void lua_setuservalue(lua_State *L, int i) { - luaL_checktype(L, i, LUA_TUSERDATA); - if (lua_isnil(L, -1)) { - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_replace(L, -2); - } - lua_setfenv(L, i); -} - -/* -** Adapted from Lua 5.2.0 -*/ -inline void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup + 1, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - int i; - lua_pushstring(L, l->name); - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -(nup + 1)); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ - } - lua_pop(L, nup); /* remove upvalues */ -} - -inline void luaL_setmetatable(lua_State *L, const char *tname) { - luaL_checkstack(L, 1, "not enough stack slots"); - luaL_getmetatable(L, tname); - lua_setmetatable(L, -2); -} - -inline int luaL_getsubtable(lua_State *L, int i, const char *name) { - int abs_i = lua_absindex(L, i); - luaL_checkstack(L, 3, "not enough stack slots"); - lua_pushstring(L, name); - lua_gettable(L, abs_i); - if (lua_istable(L, -1)) - return 1; - lua_pop(L, 1); - lua_newtable(L); - lua_pushstring(L, name); - lua_pushvalue(L, -2); - lua_settable(L, abs_i); - return 0; -} - -#ifndef SOL_LUAJIT -inline static int countlevels(lua_State *L) { - lua_Debug ar; - int li = 1, le = 1; - /* find an upper bound */ - while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } - /* do a binary search */ - while (li < le) { - int m = (li + le) / 2; - if (lua_getstack(L, m, &ar)) li = m + 1; - else le = m; - } - return le - 1; -} - -inline static int findfield(lua_State *L, int objidx, int level) { - if (level == 0 || !lua_istable(L, -1)) - return 0; /* not found */ - lua_pushnil(L); /* start 'next' loop */ - while (lua_next(L, -2)) { /* for each pair in table */ - if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ - if (lua_rawequal(L, objidx, -1)) { /* found object? */ - lua_pop(L, 1); /* remove value (but keep name) */ - return 1; - } - else if (findfield(L, objidx, level - 1)) { /* try recursively */ - lua_remove(L, -2); /* remove table (but keep name) */ - lua_pushliteral(L, "."); - lua_insert(L, -2); /* place '.' between the two names */ - lua_concat(L, 3); - return 1; - } - } - lua_pop(L, 1); /* remove value */ - } - return 0; /* not found */ -} - -inline static int pushglobalfuncname(lua_State *L, lua_Debug *ar) { - int top = lua_gettop(L); - lua_getinfo(L, "f", ar); /* push function */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - if (findfield(L, top + 1, 2)) { - lua_copy(L, -1, top + 1); /* move name to proper place */ - lua_pop(L, 2); /* remove pushed values */ - return 1; - } - else { - lua_settop(L, top); /* remove function and global table */ - return 0; - } -} - -inline static void pushfuncname(lua_State *L, lua_Debug *ar) { - if (*ar->namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, "function " LUA_QS, ar->name); - else if (*ar->what == 'm') /* main? */ - lua_pushliteral(L, "main chunk"); - else if (*ar->what == 'C') { - if (pushglobalfuncname(L, ar)) { - lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else - lua_pushliteral(L, "?"); - } - else - lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); -} - -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ - -inline void luaL_traceback(lua_State *L, lua_State *L1, - const char *msg, int level) { - lua_Debug ar; - int top = lua_gettop(L); - int numlevels = countlevels(L1); - int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; - if (msg) lua_pushfstring(L, "%s\n", msg); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - if (level == mark) { /* too many levels? */ - lua_pushliteral(L, "\n\t..."); /* add a '...' */ - level = numlevels - LEVELS2; /* and skip to last ones */ - } - else { - lua_getinfo(L1, "Slnt", &ar); - lua_pushfstring(L, "\n\t%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - lua_pushliteral(L, " in "); - pushfuncname(L, &ar); - lua_concat(L, lua_gettop(L) - top); - } - } - lua_concat(L, lua_gettop(L) - top); -} -#endif - -inline const lua_Number *lua_version(lua_State *L) { - static const lua_Number version = LUA_VERSION_NUM; - if (L == NULL) return &version; - // TODO: wonky hacks to get at the inside of the incomplete type lua_State? - //else return L->l_G->version; - else return &version; -} - -inline static void luaL_checkversion_(lua_State *L, lua_Number ver) { - const lua_Number* v = lua_version(L); - if (v != lua_version(NULL)) - luaL_error(L, "multiple Lua VMs detected"); - else if (*v != ver) - luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", - ver, *v); - /* check conversions number -> integer types */ - lua_pushnumber(L, -(lua_Number)0x1234); - if (lua_tointeger(L, -1) != -0x1234 || - lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234) - luaL_error(L, "bad conversion number->int;" - " must recompile Lua with proper settings"); - lua_pop(L, 1); -} - -inline void luaL_checkversion(lua_State* L) { - luaL_checkversion_(L, LUA_VERSION_NUM); -} - -#ifndef SOL_LUAJIT -inline int luaL_fileresult(lua_State *L, int stat, const char *fname) { - int en = errno; /* calls to Lua API may change this value */ - if (stat) { - lua_pushboolean(L, 1); - return 1; - } - else { - char buf[1024]; -#if defined(__GLIBC__) || defined(_POSIX_VERSION) - strerror_r(en, buf, 1024); -#else - strerror_s(buf, 1024, en); -#endif - lua_pushnil(L); - if (fname) - lua_pushfstring(L, "%s: %s", fname, buf); - else - lua_pushstring(L, buf); - lua_pushnumber(L, (lua_Number)en); - return 3; - } -} -#endif // luajit -#endif // Lua 5.0 or Lua 5.1 - -#if SOL_LUA_VERSION == 501 - -typedef LUAI_INT32 LUA_INT32; - -/********************************************************************/ -/* extract of 5.2's luaconf.h */ -/* detects proper defines for faster unsigned<->number conversion */ -/* see copyright notice at the end of this file */ -/********************************************************************/ - -#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE) -#define LUA_WIN /* enable goodies for regular Windows platforms */ -#endif - -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ - -/* Microsoft compiler on a Pentium (32 bit) ? */ -#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ - -#define LUA_MSASMTRICK -#define LUA_IEEEENDIAN 0 -#define LUA_NANTRICK - -/* pentium 32 bits? */ -#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ - -#define LUA_IEEE754TRICK -#define LUA_IEEELL -#define LUA_IEEEENDIAN 0 -#define LUA_NANTRICK - -/* pentium 64 bits? */ -#elif defined(__x86_64) /* }{ */ - -#define LUA_IEEE754TRICK -#define LUA_IEEEENDIAN 0 - -#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ - -#define LUA_IEEE754TRICK -#define LUA_IEEEENDIAN 1 - -#else /* }{ */ - -/* assume IEEE754 and a 32-bit integer type */ -#define LUA_IEEE754TRICK - -#endif /* } */ - -#endif /* } */ - -/********************************************************************/ -/* extract of 5.2's llimits.h */ -/* gives us lua_number2unsigned and lua_unsigned2number */ -/* see copyright notice just below this one here */ -/********************************************************************/ - -/********************************************************************* -* This file contains parts of Lua 5.2's source code: -* -* Copyright (C) 1994-2013 Lua.org, PUC-Rio. -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*********************************************************************/ - -#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */ -/* trick with Microsoft assembler for X86 */ - -#define lua_number2unsigned(i,n) \ - {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} - -#elif defined(LUA_IEEE754TRICK) /* }{ */ -/* the next trick should work on any machine using IEEE754 with -a 32-bit int type */ - -union compat52_luai_Cast { double l_d; LUA_INT32 l_p[2]; }; - -#if !defined(LUA_IEEEENDIAN) /* { */ -#define LUAI_EXTRAIEEE \ - static const union compat52_luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; -#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33) -#else -#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN -#define LUAI_EXTRAIEEE /* empty */ -#endif /* } */ - -#define lua_number2int32(i,n,t) \ - { LUAI_EXTRAIEEE \ - volatile union compat52_luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ - (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; } - -#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) - -#endif /* } */ - -/* the following definitions always work, but may be slow */ - -#if !defined(lua_number2unsigned) /* { */ -/* the following definition assures proper modulo behavior */ -#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT) -#include -#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) -#define lua_number2unsigned(i,n) \ - ((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED)) -#else -#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n)) -#endif -#endif /* } */ - -#if !defined(lua_unsigned2number) -/* on several machines, coercion from unsigned to double is slow, -so it may be worth to avoid */ -#define lua_unsigned2number(u) \ - (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u)) -#endif - -/********************************************************************/ - -inline static void compat52_call_lua(lua_State *L, char const code[], size_t len, - int nargs, int nret) { - lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); - if (lua_type(L, -1) != LUA_TFUNCTION) { - lua_pop(L, 1); - if (luaL_loadbuffer(L, code, len, "=none")) - lua_error(L); - lua_pushvalue(L, -1); - lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); - } - lua_insert(L, -nargs - 1); - lua_call(L, nargs, nret); -} - -static const char compat52_arith_code[] = { - "local op,a,b=...\n" - "if op==0 then return a+b\n" - "elseif op==1 then return a-b\n" - "elseif op==2 then return a*b\n" - "elseif op==3 then return a/b\n" - "elseif op==4 then return a%b\n" - "elseif op==5 then return a^b\n" - "elseif op==6 then return -a\n" - "end\n" -}; - -inline void lua_arith(lua_State *L, int op) { - if (op < LUA_OPADD || op > LUA_OPUNM) - luaL_error(L, "invalid 'op' argument for lua_arith"); - luaL_checkstack(L, 5, "not enough stack slots"); - if (op == LUA_OPUNM) - lua_pushvalue(L, -1); - lua_pushnumber(L, op); - lua_insert(L, -3); - compat52_call_lua(L, compat52_arith_code, - sizeof(compat52_arith_code) - 1, 3, 1); -} - -static const char compat52_compare_code[] = { - "local a,b=...\n" - "return a<=b\n" -}; - -inline int lua_compare(lua_State *L, int idx1, int idx2, int op) { - int result = 0; - switch (op) { - case LUA_OPEQ: - return lua_equal(L, idx1, idx2); - case LUA_OPLT: - return lua_lessthan(L, idx1, idx2); - case LUA_OPLE: - luaL_checkstack(L, 5, "not enough stack slots"); - idx1 = lua_absindex(L, idx1); - idx2 = lua_absindex(L, idx2); - lua_pushvalue(L, idx1); - lua_pushvalue(L, idx2); - compat52_call_lua(L, compat52_compare_code, - sizeof(compat52_compare_code) - 1, 2, 1); - result = lua_toboolean(L, -1); - lua_pop(L, 1); - return result; - default: - luaL_error(L, "invalid 'op' argument for lua_compare"); - } - return 0; -} - -inline void lua_pushunsigned(lua_State *L, lua_Unsigned n) { - lua_pushnumber(L, lua_unsigned2number(n)); -} - -inline lua_Unsigned luaL_checkunsigned(lua_State *L, int i) { - lua_Unsigned result; - lua_Number n = lua_tonumber(L, i); - if (n == 0 && !lua_isnumber(L, i)) - luaL_checktype(L, i, LUA_TNUMBER); - lua_number2unsigned(result, n); - return result; -} - -inline lua_Unsigned lua_tounsignedx(lua_State *L, int i, int *isnum) { - lua_Unsigned result; - lua_Number n = lua_tonumberx(L, i, isnum); - lua_number2unsigned(result, n); - return result; -} - -inline lua_Unsigned luaL_optunsigned(lua_State *L, int i, lua_Unsigned def) { - return luaL_opt(L, luaL_checkunsigned, i, def); -} - -inline lua_Integer lua_tointegerx(lua_State *L, int i, int *isnum) { - lua_Integer n = lua_tointeger(L, i); - if (isnum != NULL) { - *isnum = (n != 0 || lua_isnumber(L, i)); - } - return n; -} - -inline void lua_len(lua_State *L, int i) { - switch (lua_type(L, i)) { - case LUA_TSTRING: /* fall through */ - case LUA_TTABLE: - if (!luaL_callmeta(L, i, "__len")) - lua_pushnumber(L, (int)lua_objlen(L, i)); - break; - case LUA_TUSERDATA: - if (luaL_callmeta(L, i, "__len")) - break; - /* maybe fall through */ - default: - luaL_error(L, "attempt to get length of a %s value", - lua_typename(L, lua_type(L, i))); - } -} - -inline int luaL_len(lua_State *L, int i) { - int res = 0, isnum = 0; - luaL_checkstack(L, 1, "not enough stack slots"); - lua_len(L, i); - res = (int)lua_tointegerx(L, -1, &isnum); - lua_pop(L, 1); - if (!isnum) - luaL_error(L, "object length is not a number"); - return res; -} - -inline const char *luaL_tolstring(lua_State *L, int idx, size_t *len) { - if (!luaL_callmeta(L, idx, "__tostring")) { - int t = lua_type(L, idx); - switch (t) { - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - case LUA_TSTRING: - case LUA_TNUMBER: - lua_pushvalue(L, idx); - break; - case LUA_TBOOLEAN: - if (lua_toboolean(L, idx)) - lua_pushliteral(L, "true"); - else - lua_pushliteral(L, "false"); - break; - default: - lua_pushfstring(L, "%s: %p", lua_typename(L, t), - lua_topointer(L, idx)); - break; - } - } - return lua_tolstring(L, -1, len); -} - -inline void luaL_requiref(lua_State *L, char const* modname, - lua_CFunction openf, int glb) { - luaL_checkstack(L, 3, "not enough stack slots"); - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); - lua_call(L, 1, 1); - lua_getglobal(L, "package"); - if (lua_istable(L, -1) == 0) { - lua_pop(L, 1); - lua_createtable(L, 0, 16); - lua_setglobal(L, "package"); - lua_getglobal(L, "package"); - } - lua_getfield(L, -1, "loaded"); - if (lua_istable(L, -1) == 0) { - lua_pop(L, 1); - lua_createtable(L, 0, 1); - lua_setfield(L, -2, "loaded"); - lua_getfield(L, -1, "loaded"); - } - lua_replace(L, -2); - lua_pushvalue(L, -2); - lua_setfield(L, -2, modname); - lua_pop(L, 1); - if (glb) { - lua_pushvalue(L, -1); - lua_setglobal(L, modname); - } -} - -inline void luaL_buffinit(lua_State *L, luaL_Buffer_52 *B) { - /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ - B->b.p = NULL; - B->b.L = NULL; - B->b.lvl = 0; - /* reuse the buffer from the 5.1-style luaL_Buffer though! */ - B->ptr = B->b.buffer; - B->capacity = LUAL_BUFFERSIZE; - B->nelems = 0; - B->L2 = L; -} - -inline char *luaL_prepbuffsize(luaL_Buffer_52 *B, size_t s) { - if (B->capacity - B->nelems < s) { /* needs to grow */ - char* newptr = NULL; - size_t newcap = B->capacity * 2; - if (newcap - B->nelems < s) - newcap = B->nelems + s; - if (newcap < B->capacity) /* overflow */ - luaL_error(B->L2, "buffer too large"); - newptr = (char*)lua_newuserdata(B->L2, newcap); - memcpy(newptr, B->ptr, B->nelems); - if (B->ptr != B->b.buffer) - lua_replace(B->L2, -2); /* remove old buffer */ - B->ptr = newptr; - B->capacity = newcap; - } - return B->ptr + B->nelems; -} - -inline void luaL_addlstring(luaL_Buffer_52 *B, const char *s, size_t l) { - memcpy(luaL_prepbuffsize(B, l), s, l); - luaL_addsize(B, l); -} - -inline void luaL_addvalue(luaL_Buffer_52 *B) { - size_t len = 0; - const char *s = lua_tolstring(B->L2, -1, &len); - if (!s) - luaL_error(B->L2, "cannot convert value to string"); - if (B->ptr != B->b.buffer) - lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ - luaL_addlstring(B, s, len); - lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); -} - -inline void luaL_pushresult(luaL_Buffer_52 *B) { - lua_pushlstring(B->L2, B->ptr, B->nelems); - if (B->ptr != B->b.buffer) - lua_replace(B->L2, -2); /* remove userdata buffer */ -} - -#endif /* SOL_LUA_VERSION == 501 */ - -#endif // SOL_5_X_X_INL -// end of sol/compatibility/5.x.x.inl - -#if defined(__cplusplus) && !defined(SOL_USING_CXX_LUA) -} -#endif - -#endif // SOL_NO_COMPAT - -// end of sol/compatibility.hpp - -// beginning of sol/in_place.hpp - -namespace sol { - - namespace detail { - struct in_place_of {}; - template - struct in_place_of_i {}; - template - struct in_place_of_t {}; - } // detail - - struct in_place_tag { struct init {}; constexpr in_place_tag(init) {} in_place_tag() = delete; }; - constexpr inline in_place_tag in_place(detail::in_place_of) { return in_place_tag(in_place_tag::init()); } - template - constexpr inline in_place_tag in_place(detail::in_place_of_t) { return in_place_tag(in_place_tag::init()); } - template - constexpr inline in_place_tag in_place(detail::in_place_of_i) { return in_place_tag(in_place_tag::init()); } - - using in_place_t = in_place_tag(&)(detail::in_place_of); - template - using in_place_type_t = in_place_tag(&)(detail::in_place_of_t); - template - using in_place_index_t = in_place_tag(&)(detail::in_place_of_i); - -} // sol - -// end of sol/in_place.hpp - -#if defined(SOL_USE_BOOST) -#include -#else -// beginning of sol/optional_implementation.hpp - -# ifndef SOL_OPTIONAL_IMPLEMENTATION_HPP -# define SOL_OPTIONAL_IMPLEMENTATION_HPP - -# include -# include -# include -# include -# include -# include -# include -#ifdef SOL_NO_EXCEPTIONS -#include -#endif // Exceptions - -# define TR2_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false - -# if defined __GNUC__ // NOTE: GNUC is also defined for Clang -# if (__GNUC__ >= 5) -# define TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# endif -# -# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# endif -# -# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# endif -# endif -# -# if defined __clang_major__ -# if (__clang_major__ == 3 && __clang_minor__ >= 5) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# elif (__clang_major__ > 3) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# endif -# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# endif -# endif -# -# if defined _MSC_VER -# if (_MSC_VER >= 1900) -# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# endif -# endif - -# if defined __clang__ -# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif -# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif - -# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 -# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr -# else -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 -# define OPTIONAL_CONSTEXPR_INIT_LIST -# endif - -# if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || (defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L)) -# define OPTIONAL_HAS_MOVE_ACCESSORS 1 -# else -# define OPTIONAL_HAS_MOVE_ACCESSORS 0 -# endif - -# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr -# if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || ((defined __cplusplus) && (__cplusplus == 201103L)) -# define OPTIONAL_MUTABLE_CONSTEXPR -# else -# define OPTIONAL_MUTABLE_CONSTEXPR constexpr -# endif - -# if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -#pragma warning( push ) -#pragma warning( disable : 4814 ) -#endif - -namespace sol { - - // BEGIN workaround for missing is_trivially_destructible -# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it: it is already there -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else - template - using is_trivially_destructible = ::std::has_trivial_destructor; -# endif - // END workaround for missing is_trivially_destructible - -# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else - - template - struct is_nothrow_move_constructible - { - constexpr static bool value = ::std::is_nothrow_constructible::value; - }; - - template - struct is_assignable - { - template - constexpr static bool has_assign(...) { return false; } - - template () = ::std::declval(), true)) > - // the comma operator is necessary for the cases where operator= returns void - constexpr static bool has_assign(bool) { return true; } - - constexpr static bool value = has_assign(true); - }; - - template - struct is_nothrow_move_assignable - { - template - struct has_nothrow_move_assign { - constexpr static bool value = false; - }; - - template - struct has_nothrow_move_assign { - constexpr static bool value = noexcept(::std::declval() = ::std::declval()); - }; - - constexpr static bool value = has_nothrow_move_assign::value>::value; - }; - // end workaround - -# endif - - template class optional; - - // 20.5.5, optional for lvalue reference types - template class optional; - - // workaround: std utility functions aren't constexpr yet - template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type& t) noexcept - { - return static_cast(t); - } - - template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type&& t) noexcept - { - static_assert(!::std::is_lvalue_reference::value, "!!"); - return static_cast(t); - } - - template inline constexpr typename ::std::remove_reference::type&& constexpr_move(T&& t) noexcept - { - return static_cast::type&&>(t); - } - -#if defined NDEBUG -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) -#else -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) -#endif - - namespace detail_ - { - - // static_addressof: a constexpr version of addressof - template - struct has_overloaded_addressof - { - template - constexpr static bool has_overload(...) { return false; } - - template ().operator&()) > - constexpr static bool has_overload(bool) { return true; } - - constexpr static bool value = has_overload(true); - }; - - template )> - constexpr T* static_addressof(T& ref) - { - return &ref; - } - - template )> - T* static_addressof(T& ref) - { - return ::std::addressof(ref); - } - - // the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A - template - constexpr U convert(U v) { return v; } - - } // namespace detail_ - - constexpr struct trivial_init_t {} trivial_init{}; - - // 20.5.7, Disengaged state indicator - struct nullopt_t - { - struct init {}; - constexpr explicit nullopt_t(init) {} - }; - constexpr nullopt_t nullopt{ nullopt_t::init() }; - - // 20.5.8, class bad_optional_access - class bad_optional_access : public ::std::logic_error { - public: - explicit bad_optional_access(const ::std::string& what_arg) : ::std::logic_error{ what_arg } {} - explicit bad_optional_access(const char* what_arg) : ::std::logic_error{ what_arg } {} - }; - - template - struct alignas(T) optional_base { - char storage_[sizeof(T)]; - bool init_; - - constexpr optional_base() noexcept : storage_(), init_(false) {}; - - explicit optional_base(const T& v) : storage_(), init_(true) { - new (&storage())T(v); - } - - explicit optional_base(T&& v) : storage_(), init_(true) { - new (&storage())T(constexpr_move(v)); - } - - template explicit optional_base(in_place_t, Args&&... args) - : init_(true), storage_() { - new (&storage())T(constexpr_forward(args)...); - } - - template >)> - explicit optional_base(in_place_t, ::std::initializer_list il, Args&&... args) - : init_(true), storage_() { - new (&storage())T(il, constexpr_forward(args)...); - } -#if defined __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif - T& storage() { - return *reinterpret_cast(&storage_[0]); - } - - constexpr const T& storage() const { - return *reinterpret_cast(&storage_[0]); - } -#if defined __GNUC__ -#pragma GCC diagnostic pop -#endif - - ~optional_base() { if (init_) { storage().T::~T(); } } - }; - -#if defined __GNUC__ && !defined TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ - // Sorry, GCC 4.x; you're just a piece of shit - template - using constexpr_optional_base = optional_base; -#else - template - struct alignas(T) constexpr_optional_base { - char storage_[sizeof(T)]; - bool init_; - constexpr constexpr_optional_base() noexcept : storage_(), init_(false) {} - - explicit constexpr constexpr_optional_base(const T& v) : storage_(), init_(true) { - new (&storage())T(v); - } - - explicit constexpr constexpr_optional_base(T&& v) : storage_(), init_(true) { - new (&storage())T(constexpr_move(v)); - } - - template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) - : init_(true), storage_() { - new (&storage())T(constexpr_forward(args)...); - } - - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, ::std::initializer_list il, Args&&... args) - : init_(true), storage_() { - new (&storage())T(il, constexpr_forward(args)...); - } - -#if defined __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif - T& storage() { - return (*reinterpret_cast(&storage_[0])); - } - - constexpr const T& storage() const { - return (*reinterpret_cast(&storage_[0])); - } -#if defined __GNUC__ -#pragma GCC diagnostic pop -#endif - - ~constexpr_optional_base() = default; - }; -#endif - - template - using OptionalBase = typename ::std::conditional< - ::std::is_trivially_destructible::value, - constexpr_optional_base::type>, - optional_base::type> - >::type; - - template - class optional : private OptionalBase - { - static_assert(!::std::is_same::type, nullopt_t>::value, "bad T"); - static_assert(!::std::is_same::type, in_place_t>::value, "bad T"); - - constexpr bool initialized() const noexcept { return OptionalBase::init_; } - typename ::std::remove_const::type* dataptr() { return ::std::addressof(OptionalBase::storage()); } - constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage()); } - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 - constexpr const T& contained_val() const& { return OptionalBase::storage(); } -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return ::std::move(OptionalBase::storage()); } - OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage(); } -# else - T& contained_val() & { return OptionalBase::storage(); } - T&& contained_val() && { return ::std::move(OptionalBase::storage()); } -# endif -# else - constexpr const T& contained_val() const { return OptionalBase::storage(); } - T& contained_val() { return OptionalBase::storage(); } -# endif - - void clear() noexcept { - if (initialized()) dataptr()->T::~T(); - OptionalBase::init_ = false; - } - - template - void initialize(Args&&... args) noexcept(noexcept(T(::std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(::std::forward(args)...); - OptionalBase::init_ = true; - } - - template - void initialize(::std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, ::std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(il, ::std::forward(args)...); - OptionalBase::init_ = true; - } - - public: - typedef T value_type; - - // 20.5.5.1, constructors - constexpr optional() noexcept : OptionalBase() {}; - constexpr optional(nullopt_t) noexcept : OptionalBase() {}; - - optional(const optional& rhs) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(*rhs); - OptionalBase::init_ = true; - } - } - - optional(const optional& rhs) : optional() - { - if (rhs) { - ::new (static_cast(dataptr())) T(*rhs); - OptionalBase::init_ = true; - } - } - - optional(optional&& rhs) noexcept(::std::is_nothrow_move_constructible::value) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(::std::move(*rhs)); - OptionalBase::init_ = true; - } - } - - constexpr optional(const T& v) : OptionalBase(v) {} - - constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} - - template - explicit constexpr optional(in_place_t, Args&&... args) - : OptionalBase(in_place, constexpr_forward(args)...) {} - - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, ::std::initializer_list il, Args&&... args) - : OptionalBase(in_place, il, constexpr_forward(args)...) {} - - // 20.5.4.2, Destructor - ~optional() = default; - - // 20.5.4.3, assignment - optional& operator=(nullopt_t) noexcept - { - clear(); - return *this; - } - - optional& operator=(const optional& rhs) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); - else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; - return *this; - } - - optional& operator=(optional&& rhs) - noexcept(::std::is_nothrow_move_assignable::value && ::std::is_nothrow_move_constructible::value) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(::std::move(*rhs)); - else if (initialized() == true && rhs.initialized() == true) contained_val() = ::std::move(*rhs); - return *this; - } - - template - auto operator=(U&& v) - -> typename ::std::enable_if - < - ::std::is_same::type, T>::value, - optional& - >::type - { - if (initialized()) { contained_val() = ::std::forward(v); } - else { initialize(::std::forward(v)); } - return *this; - } - - template - void emplace(Args&&... args) - { - clear(); - initialize(::std::forward(args)...); - } - - template - void emplace(::std::initializer_list il, Args&&... args) - { - clear(); - initialize(il, ::std::forward(args)...); - } - - // 20.5.4.4, Swap - void swap(optional& rhs) noexcept(::std::is_nothrow_move_constructible::value && noexcept(swap(::std::declval(), ::std::declval()))) - { - if (initialized() == true && rhs.initialized() == false) { rhs.initialize(::std::move(**this)); clear(); } - else if (initialized() == false && rhs.initialized() == true) { initialize(::std::move(*rhs)); rhs.clear(); } - else if (initialized() == true && rhs.initialized() == true) { using ::std::swap; swap(**this, *rhs); } - } - - // 20.5.4.5, Observers - - explicit constexpr operator bool() const noexcept { return initialized(); } - - constexpr T const* operator ->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - - OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { - assert(initialized()); - return dataptr(); - } - - constexpr T const& operator *() const& { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { - assert(initialized()); - return contained_val(); - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { - assert(initialized()); - return constexpr_move(contained_val()); - } - - constexpr T const& value() const& { - return initialized() ? - contained_val() -#ifdef SOL_NO_EXCEPTIONS - // we can't abort here - // because there's no constexpr abort - : *(T*)nullptr; -#else - : (throw bad_optional_access("bad optional access"), contained_val()); -#endif - } - - OPTIONAL_MUTABLE_CONSTEXPR T& value() & { - return initialized() ? - contained_val() -#ifdef SOL_NO_EXCEPTIONS - : *(T*)nullptr; -#else - : (throw bad_optional_access("bad optional access"), contained_val()); -#endif - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { - return initialized() ? - contained_val() -#ifdef SOL_NO_EXCEPTIONS - // we can't abort here - // because there's no constexpr abort - : std::move(*(T*)nullptr); -#else - : (throw bad_optional_access("bad optional access"), contained_val()); -#endif - } - -# else - - T* operator ->() { - assert(initialized()); - return dataptr(); - } - - constexpr T const& operator *() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - T& operator *() { - assert(initialized()); - return contained_val(); - } - - constexpr T const& value() const { - return initialized() ? - contained_val() -#ifdef SOL_NO_EXCEPTIONS - // we can't abort here - // because there's no constexpr abort - : *(T*)nullptr; -#else - : (throw bad_optional_access("bad optional access"), contained_val()); -#endif - } - - T& value() { - return initialized() ? - contained_val() -#ifdef SOL_NO_EXCEPTIONS - // we can abort here - // but the others are constexpr, so we can't... - : (std::abort(), *(T*)nullptr); -#else - : (throw bad_optional_access("bad optional access"), contained_val()); -#endif - } - -# endif - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 - - template - constexpr T value_or(V&& v) const& - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - - template - OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } - -# else - - template - T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } - -# endif - -# else - - template - constexpr T value_or(V&& v) const - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - -# endif - - }; - - template - class optional - { - static_assert(!::std::is_same::value, "bad T"); - static_assert(!::std::is_same::value, "bad T"); - T* ref; - - public: - - // 20.5.5.1, construction/destruction - constexpr optional() noexcept : ref(nullptr) {} - - constexpr optional(nullopt_t) noexcept : ref(nullptr) {} - - constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} - - optional(T&&) = delete; - - constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} - - explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} - - explicit optional(in_place_t, T&&) = delete; - - ~optional() = default; - - // 20.5.5.2, mutation - optional& operator=(nullopt_t) noexcept { - ref = nullptr; - return *this; - } - - // optional& operator=(const optional& rhs) noexcept { - // ref = rhs.ref; - // return *this; - // } - - // optional& operator=(optional&& rhs) noexcept { - // ref = rhs.ref; - // return *this; - // } - - template - auto operator=(U&& rhs) noexcept - -> typename ::std::enable_if - < - ::std::is_same::type, optional>::value, - optional& - >::type - { - ref = rhs.ref; - return *this; - } - - template - auto operator=(U&& rhs) noexcept - -> typename ::std::enable_if - < - !::std::is_same::type, optional>::value, - optional& - >::type - = delete; - - void emplace(T& v) noexcept { - ref = detail_::static_addressof(v); - } - - void emplace(T&&) = delete; - - void swap(optional& rhs) noexcept - { - ::std::swap(ref, rhs.ref); - } - - // 20.5.5.3, observers - constexpr T* operator->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); - } - - constexpr T& operator*() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); - } - - constexpr T& value() const { -#ifdef SOL_NO_EXCEPTIONS - return *ref; -#else - return ref ? *ref - : (throw bad_optional_access("bad optional access"), *ref); -#endif // Exceptions - } - - explicit constexpr operator bool() const noexcept { - return ref != nullptr; - } - - template - constexpr T& value_or(V&& v) const - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - }; - - template - class optional - { - static_assert(sizeof(T) == 0, "optional rvalue references disallowed"); - }; - - // 20.5.8, Relational operators - template constexpr bool operator==(const optional& x, const optional& y) - { - return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; - } - - template constexpr bool operator!=(const optional& x, const optional& y) - { - return !(x == y); - } - - template constexpr bool operator<(const optional& x, const optional& y) - { - return (!y) ? false : (!x) ? true : *x < *y; - } - - template constexpr bool operator>(const optional& x, const optional& y) - { - return (y < x); - } - - template constexpr bool operator<=(const optional& x, const optional& y) - { - return !(y < x); - } - - template constexpr bool operator>=(const optional& x, const optional& y) - { - return !(x < y); - } - - // 20.5.9, Comparison with nullopt - template constexpr bool operator==(const optional& x, nullopt_t) noexcept - { - return (!x); - } - - template constexpr bool operator==(nullopt_t, const optional& x) noexcept - { - return (!x); - } - - template constexpr bool operator!=(const optional& x, nullopt_t) noexcept - { - return bool(x); - } - - template constexpr bool operator!=(nullopt_t, const optional& x) noexcept - { - return bool(x); - } - - template constexpr bool operator<(const optional&, nullopt_t) noexcept - { - return false; - } - - template constexpr bool operator<(nullopt_t, const optional& x) noexcept - { - return bool(x); - } - - template constexpr bool operator<=(const optional& x, nullopt_t) noexcept - { - return (!x); - } - - template constexpr bool operator<=(nullopt_t, const optional&) noexcept - { - return true; - } - - template constexpr bool operator>(const optional& x, nullopt_t) noexcept - { - return bool(x); - } - - template constexpr bool operator>(nullopt_t, const optional&) noexcept - { - return false; - } - - template constexpr bool operator>=(const optional&, nullopt_t) noexcept - { - return true; - } - - template constexpr bool operator>=(nullopt_t, const optional& x) noexcept - { - return (!x); - } - - // 20.5.10, Comparison with T - template constexpr bool operator==(const optional& x, const T& v) - { - return bool(x) ? *x == v : false; - } - - template constexpr bool operator==(const T& v, const optional& x) - { - return bool(x) ? v == *x : false; - } - - template constexpr bool operator!=(const optional& x, const T& v) - { - return bool(x) ? *x != v : true; - } - - template constexpr bool operator!=(const T& v, const optional& x) - { - return bool(x) ? v != *x : true; - } - - template constexpr bool operator<(const optional& x, const T& v) - { - return bool(x) ? *x < v : true; - } - - template constexpr bool operator>(const T& v, const optional& x) - { - return bool(x) ? v > *x : true; - } - - template constexpr bool operator>(const optional& x, const T& v) - { - return bool(x) ? *x > v : false; - } - - template constexpr bool operator<(const T& v, const optional& x) - { - return bool(x) ? v < *x : false; - } - - template constexpr bool operator>=(const optional& x, const T& v) - { - return bool(x) ? *x >= v : false; - } - - template constexpr bool operator<=(const T& v, const optional& x) - { - return bool(x) ? v <= *x : false; - } - - template constexpr bool operator<=(const optional& x, const T& v) - { - return bool(x) ? *x <= v : true; - } - - template constexpr bool operator>=(const T& v, const optional& x) - { - return bool(x) ? v >= *x : true; - } - - // Comparison of optional with T - template constexpr bool operator==(const optional& x, const T& v) - { - return bool(x) ? *x == v : false; - } - - template constexpr bool operator==(const T& v, const optional& x) - { - return bool(x) ? v == *x : false; - } - - template constexpr bool operator!=(const optional& x, const T& v) - { - return bool(x) ? *x != v : true; - } - - template constexpr bool operator!=(const T& v, const optional& x) - { - return bool(x) ? v != *x : true; - } - - template constexpr bool operator<(const optional& x, const T& v) - { - return bool(x) ? *x < v : true; - } - - template constexpr bool operator>(const T& v, const optional& x) - { - return bool(x) ? v > *x : true; - } - - template constexpr bool operator>(const optional& x, const T& v) - { - return bool(x) ? *x > v : false; - } - - template constexpr bool operator<(const T& v, const optional& x) - { - return bool(x) ? v < *x : false; - } - - template constexpr bool operator>=(const optional& x, const T& v) - { - return bool(x) ? *x >= v : false; - } - - template constexpr bool operator<=(const T& v, const optional& x) - { - return bool(x) ? v <= *x : false; - } - - template constexpr bool operator<=(const optional& x, const T& v) - { - return bool(x) ? *x <= v : true; - } - - template constexpr bool operator>=(const T& v, const optional& x) - { - return bool(x) ? v >= *x : true; - } - - // Comparison of optional with T - template constexpr bool operator==(const optional& x, const T& v) - { - return bool(x) ? *x == v : false; - } - - template constexpr bool operator==(const T& v, const optional& x) - { - return bool(x) ? v == *x : false; - } - - template constexpr bool operator!=(const optional& x, const T& v) - { - return bool(x) ? *x != v : true; - } - - template constexpr bool operator!=(const T& v, const optional& x) - { - return bool(x) ? v != *x : true; - } - - template constexpr bool operator<(const optional& x, const T& v) - { - return bool(x) ? *x < v : true; - } - - template constexpr bool operator>(const T& v, const optional& x) - { - return bool(x) ? v > *x : true; - } - - template constexpr bool operator>(const optional& x, const T& v) - { - return bool(x) ? *x > v : false; - } - - template constexpr bool operator<(const T& v, const optional& x) - { - return bool(x) ? v < *x : false; - } - - template constexpr bool operator>=(const optional& x, const T& v) - { - return bool(x) ? *x >= v : false; - } - - template constexpr bool operator<=(const T& v, const optional& x) - { - return bool(x) ? v <= *x : false; - } - - template constexpr bool operator<=(const optional& x, const T& v) - { - return bool(x) ? *x <= v : true; - } - - template constexpr bool operator>=(const T& v, const optional& x) - { - return bool(x) ? v >= *x : true; - } - - // 20.5.12, Specialized algorithms - template - void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) { - x.swap(y); - } - - template - constexpr optional::type> make_optional(T&& v) { - return optional::type>(constexpr_forward(v)); - } - - template - constexpr optional make_optional(::std::reference_wrapper v) { - return optional(v.get()); - } - -} // namespace - -namespace std -{ - template - struct hash> { - typedef typename hash::result_type result_type; - typedef sol::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? ::std::hash{}(*arg) : result_type{}; - } - }; - - template - struct hash> { - typedef typename hash::result_type result_type; - typedef sol::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? ::std::hash{}(*arg) : result_type{}; - } - }; -} - -# if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -#pragma warning( pop ) -#endif - -# undef TR2_OPTIONAL_REQUIRES -# undef TR2_OPTIONAL_ASSERTED_EXPRESSION - -# endif // SOL_OPTIONAL_IMPLEMENTATION_HPP -// end of sol/optional_implementation.hpp - -#endif // Boost vs. Better optional - -namespace sol { - -#if defined(SOL_USE_BOOST) - template - using optional = boost::optional; - using nullopt_t = boost::none_t; - const nullopt_t nullopt = boost::none; -#endif // Boost vs. Better optional - -} // sol - -// end of sol/optional.hpp - -// beginning of sol/string_shim.hpp - -namespace sol { - namespace string_detail { - struct string_shim { - std::size_t s; - const char* p; - - string_shim(const std::string& r) : string_shim(r.data(), r.size()) {} - string_shim(const char* ptr) : string_shim(ptr, std::char_traits::length(ptr)) {} - string_shim(const char* ptr, std::size_t sz) : s(sz), p(ptr) {} - - static int compare(const char* lhs_p, std::size_t lhs_sz, const char* rhs_p, std::size_t rhs_sz) { - int result = std::char_traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); - if (result != 0) - return result; - if (lhs_sz < rhs_sz) - return -1; - if (lhs_sz > rhs_sz) - return 1; - return 0; - } - - const char* c_str() const { - return p; - } - - const char* data() const { - return p; - } - - std::size_t size() const { - return s; - } - - bool operator==(const string_shim& r) const { - return compare(p, s, r.data(), r.size()) == 0; - } - - bool operator==(const char* r) const { - return compare(r, std::char_traits::length(r), p, s) == 0; - } - - bool operator==(const std::string& r) const { - return compare(r.data(), r.size(), p, s) == 0; - } - - bool operator!=(const string_shim& r) const { - return !(*this == r); - } - - bool operator!=(const char* r) const { - return !(*this == r); - } - - bool operator!=(const std::string& r) const { - return !(*this == r); - } - }; - } -} - -// end of sol/string_shim.hpp - -#include - -namespace sol { - namespace detail { -#ifdef SOL_NO_EXCEPTIONS - template - int static_trampoline(lua_State* L) { - return f(L); - } - - template - int trampoline(lua_State* L, Fx&& f, Args&&... args) { - return f(L, std::forward(args)...); - } - - inline int c_trampoline(lua_State* L, lua_CFunction f) { - return trampoline(L, f); - } -#else - template - int static_trampoline(lua_State* L) { - try { - return f(L); - } - catch (const char *s) { - lua_pushstring(L, s); - } - catch (const std::exception& e) { - lua_pushstring(L, e.what()); - } -#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) - catch (...) { - std::exception_ptr eptr = std::current_exception(); - lua_pushstring(L, "caught (...) exception"); - } -#endif - return lua_error(L); - } - - template - int trampoline(lua_State* L, Fx&& f, Args&&... args) { - try { - return f(L, std::forward(args)...); - } - catch (const char *s) { - lua_pushstring(L, s); - } - catch (const std::exception& e) { - lua_pushstring(L, e.what()); - } -#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) - catch (...) { - lua_pushstring(L, "caught (...) exception"); - } -#endif - return lua_error(L); - } - - inline int c_trampoline(lua_State* L, lua_CFunction f) { - return trampoline(L, f); - } -#endif // Exceptions vs. No Exceptions - - template - struct unique_usertype {}; - - template - struct implicit_wrapper { - T& item; - implicit_wrapper(T* item) : item(*item) {} - implicit_wrapper(T& item) : item(item) {} - operator T& () { - return item; - } - operator T* () { - return std::addressof(item); - } - }; - - struct unchecked_t {}; - const unchecked_t unchecked = unchecked_t{}; - } // detail - - struct lua_nil_t {}; - const lua_nil_t lua_nil{}; - inline bool operator==(lua_nil_t, lua_nil_t) { return true; } - inline bool operator!=(lua_nil_t, lua_nil_t) { return false; } -#ifndef __OBJC__ - typedef lua_nil_t nil_t; - const nil_t nil{}; -#endif - - struct metatable_t {}; - const metatable_t metatable_key = {}; - - struct env_t {}; - const env_t env_key = {}; - - struct no_metatable_t {}; - const no_metatable_t no_metatable = {}; - - typedef std::remove_pointer_t lua_r_CFunction; - - template - struct unique_usertype_traits { - typedef T type; - typedef T actual_type; - static const bool value = false; - - template - static bool is_null(U&&) { - return false; - } - - template - static auto get(U&& value) { - return std::addressof(detail::deref(value)); - } - }; - - template - struct unique_usertype_traits> { - typedef T type; - typedef std::shared_ptr actual_type; - static const bool value = true; - - static bool is_null(const actual_type& p) { - return p == nullptr; - } - - static type* get(const actual_type& p) { - return p.get(); - } - }; - - template - struct unique_usertype_traits> { - typedef T type; - typedef std::unique_ptr actual_type; - static const bool value = true; - - static bool is_null(const actual_type& p) { - return p == nullptr; - } - - static type* get(const actual_type& p) { - return p.get(); - } - }; - - template - struct non_null {}; - - template - struct function_sig {}; - - struct upvalue_index { - int index; - upvalue_index(int idx) : index(lua_upvalueindex(idx)) {} - operator int() const { return index; } - }; - - struct raw_index { - int index; - raw_index(int i) : index(i) {} - operator int() const { return index; } - }; - - struct absolute_index { - int index; - absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {} - operator int() const { return index; } - }; - - struct ref_index { - int index; - ref_index(int idx) : index(idx) {} - operator int() const { return index; } - }; - - struct lightuserdata_value { - void* value; - lightuserdata_value(void* data) : value(data) {} - operator void*() const { return value; } - }; - - struct userdata_value { - void* value; - userdata_value(void* data) : value(data) {} - operator void*() const { return value; } - }; - - template - struct light { - L* value; - - light(L& x) : value(std::addressof(x)) {} - light(L* x) : value(x) {} - light(void* x) : value(static_cast(x)) {} - operator L* () const { return value; } - operator L& () const { return *value; } - }; - - template - auto make_light(T& l) { - typedef meta::unwrapped_t>> L; - return light(l); - } - - template - struct user { - U value; - - user(U x) : value(std::move(x)) {} - operator U* () { return std::addressof(value); } - operator U& () { return value; } - operator const U& () const { return value; } - }; - - template - auto make_user(T&& u) { - typedef meta::unwrapped_t> U; - return user(std::forward(u)); - } - - template - struct metatable_registry_key { - T key; - - metatable_registry_key(T key) : key(std::forward(key)) {} - }; - - template - auto meta_registry_key(T&& key) { - typedef meta::unqualified_t K; - return metatable_registry_key(std::forward(key)); - } - - template - struct closure { - lua_CFunction c_function; - std::tuple upvalues; - closure(lua_CFunction f, Upvalues... targetupvalues) : c_function(f), upvalues(std::forward(targetupvalues)...) {} - }; - - template <> - struct closure<> { - lua_CFunction c_function; - int upvalues; - closure(lua_CFunction f, int upvalue_count = 0) : c_function(f), upvalues(upvalue_count) {} - }; - - typedef closure<> c_closure; - - template - closure make_closure(lua_CFunction f, Args&&... args) { - return closure(f, std::forward(args)...); - } - - template - struct function_arguments { - std::tuple arguments; - template , function_arguments>> = meta::enabler> - function_arguments(Arg&& arg, Args&&... args) : arguments(std::forward(arg), std::forward(args)...) {} - }; - - template , typename... Args> - auto as_function(Args&&... args) { - return function_arguments...>(std::forward(args)...); - } - - template , typename... Args> - auto as_function_reference(Args&&... args) { - return function_arguments(std::forward(args)...); - } - - template - struct as_table_t { - T source; - template - as_table_t(Args&&... args) : source(std::forward(args)...) {} - - operator std::add_lvalue_reference_t () { - return source; - } - }; - - template - struct nested { - T source; - - template - nested(Args&&... args) : source(std::forward(args)...) {} - - operator std::add_lvalue_reference_t() { - return source; - } - }; - - template - as_table_t as_table(T&& container) { - return as_table_t(std::forward(container)); - } - - struct this_state { - lua_State* L; - operator lua_State* () const { - return L; - } - lua_State* operator-> () const { - return L; - } - }; - - struct new_table { - int sequence_hint = 0; - int map_hint = 0; - - new_table() = default; - new_table(const new_table&) = default; - new_table(new_table&&) = default; - new_table& operator=(const new_table&) = default; - new_table& operator=(new_table&&) = default; - - new_table(int sequence_hint, int map_hint = 0) : sequence_hint(sequence_hint), map_hint(map_hint) {} - }; - - enum class call_syntax { - dot = 0, - colon = 1 - }; - - enum class call_status : int { - ok = LUA_OK, - yielded = LUA_YIELD, - runtime = LUA_ERRRUN, - memory = LUA_ERRMEM, - handler = LUA_ERRERR, - gc = LUA_ERRGCMM, - syntax = LUA_ERRSYNTAX, - file = LUA_ERRFILE, - }; - - enum class thread_status : int { - ok = LUA_OK, - yielded = LUA_YIELD, - runtime = LUA_ERRRUN, - memory = LUA_ERRMEM, - gc = LUA_ERRGCMM, - handler = LUA_ERRERR, - dead = -1, - }; - - enum class load_status : int { - ok = LUA_OK, - syntax = LUA_ERRSYNTAX, - memory = LUA_ERRMEM, - gc = LUA_ERRGCMM, - file = LUA_ERRFILE, - }; - - enum class type : int { - none = LUA_TNONE, - lua_nil = LUA_TNIL, -#ifndef __OBJC__ - nil = lua_nil, -#endif // Objective C++ Keyword - string = LUA_TSTRING, - number = LUA_TNUMBER, - thread = LUA_TTHREAD, - boolean = LUA_TBOOLEAN, - function = LUA_TFUNCTION, - userdata = LUA_TUSERDATA, - lightuserdata = LUA_TLIGHTUSERDATA, - table = LUA_TTABLE, - poly = none | lua_nil | string | number | thread | - table | boolean | function | userdata | lightuserdata - }; - - inline const std::string& to_string(call_status c) { - static const std::array names{{ - "ok", - "yielded", - "runtime", - "memory", - "handler", - "gc", - "syntax", - "file", - }}; - switch (c) { - case call_status::ok: - return names[0]; - case call_status::yielded: - return names[1]; - case call_status::runtime: - return names[2]; - case call_status::memory: - return names[3]; - case call_status::handler: - return names[4]; - case call_status::gc: - return names[5]; - case call_status::syntax: - return names[6]; - case call_status::file: - return names[7]; - } - return names[0]; - } - - inline const std::string& to_string(load_status c) { - static const std::array names{ { - "ok", - "memory", - "gc", - "syntax", - "file", - } }; - switch (c) { - case load_status::ok: - return names[0]; - case load_status::memory: - return names[1]; - case load_status::gc: - return names[2]; - case load_status::syntax: - return names[3]; - case load_status::file: - return names[4]; - } - return names[0]; - } - - enum class meta_function { - construct, - index, - new_index, - mode, - call, - call_function = call, - metatable, - to_string, - length, - unary_minus, - addition, - subtraction, - multiplication, - division, - modulus, - power_of, - involution = power_of, - concatenation, - equal_to, - less_than, - less_than_or_equal_to, - garbage_collect, - floor_division, - bitwise_left_shift, - bitwise_right_shift, - bitwise_not, - bitwise_and, - bitwise_or, - bitwise_xor, - pairs, - next - }; - - typedef meta_function meta_method; - - inline const std::array& meta_function_names() { - static const std::array names = { { - "new", - "__index", - "__newindex", - "__mode", - "__call", - "__mt", - "__tostring", - "__len", - "__unm", - "__add", - "__sub", - "__mul", - "__div", - "__mod", - "__pow", - "__concat", - "__eq", - "__lt", - "__le", - "__gc", - - "__idiv", - "__shl", - "__shr", - "__bnot", - "__band", - "__bor", - "__bxor", - - "__pairs", - "__next" - } }; - return names; - } - - inline const std::string& to_string(meta_function mf) { - return meta_function_names()[static_cast(mf)]; - } - - inline type type_of(lua_State* L, int index) { - return static_cast(lua_type(L, index)); - } - - inline int type_panic(lua_State* L, int index, type expected, type actual) { - return luaL_error(L, "stack index %d, expected %s, received %s", index, - expected == type::poly ? "anything" : lua_typename(L, static_cast(expected)), - expected == type::poly ? "anything" : lua_typename(L, static_cast(actual)) - ); - } - - // Specify this function as the handler for lua::check if you know there's nothing wrong - inline int no_panic(lua_State*, int, type, type) noexcept { - return 0; - } - - inline void type_error(lua_State* L, int expected, int actual) { - luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual)); - } - - inline void type_error(lua_State* L, type expected, type actual) { - type_error(L, static_cast(expected), static_cast(actual)); - } - - inline void type_assert(lua_State* L, int index, type expected, type actual) { - if (expected != type::poly && expected != actual) { - type_panic(L, index, expected, actual); - } - } - - inline void type_assert(lua_State* L, int index, type expected) { - type actual = type_of(L, index); - type_assert(L, index, expected, actual); - } - - inline std::string type_name(lua_State* L, type t) { - return lua_typename(L, static_cast(t)); - } - - class reference; - class stack_reference; - template - struct proxy; - template - class usertype; - template - class basic_table_core; - template - using table_core = basic_table_core; - template - using stack_table_core = basic_table_core; - template - using basic_table = basic_table_core; - typedef table_core table; - typedef table_core global_table; - typedef stack_table_core stack_table; - typedef stack_table_core stack_global_table; - template - struct basic_environment; - using environment = basic_environment; - using stack_environment = basic_environment; - template - class basic_function; - template - class basic_protected_function; - using protected_function = basic_protected_function; - using stack_protected_function = basic_protected_function; - using unsafe_function = basic_function; - using safe_function = basic_protected_function; - using stack_unsafe_function = basic_function; - using stack_safe_function = basic_protected_function; -#ifdef SOL_SAFE_FUNCTIONS - using function = protected_function; - using stack_function = stack_protected_function; -#else - using function = unsafe_function; - using stack_function = stack_unsafe_function; -#endif - template - class basic_object; - template - class basic_userdata; - template - class basic_lightuserdata; - struct variadic_args; - using object = basic_object; - using stack_object = basic_object; - using userdata = basic_userdata; - using stack_userdata = basic_userdata; - using lightuserdata = basic_lightuserdata; - using stack_lightuserdata = basic_lightuserdata; - class coroutine; - class thread; - struct variadic_args; - struct this_state; - - namespace detail { - template - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant { }; - - template <> - struct lua_type_of : std::integral_constant { }; - - template <> - struct lua_type_of : std::integral_constant { }; - - template <> - struct lua_type_of : std::integral_constant { }; - - template - struct lua_type_of> : std::integral_constant { }; - - template <> - struct lua_type_of : std::integral_constant { }; - - template - struct lua_type_of> : std::integral_constant { }; - - template <> - struct lua_type_of : std::integral_constant { }; - - template <> - struct lua_type_of : std::integral_constant { }; - - template - struct lua_type_of> : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template - struct lua_type_of> : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of : std::integral_constant {}; - - template - struct lua_type_of::value>> : std::integral_constant {}; - - template - struct lua_type_of::value>> : std::integral_constant {}; - - template - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - - template <> - struct is_container : std::false_type {}; - - template - struct is_container>::value>> : std::true_type {}; - - template <> - struct lua_type_of : std::integral_constant {}; - - template class V, typename... Args> - struct accumulate : std::integral_constant {}; - - template class V, typename T, typename... Args> - struct accumulate : accumulate::value, V, Args...> {}; - } // detail - - template - struct is_unique_usertype : std::integral_constant::value> {}; - - template - struct lua_type_of : detail::lua_type_of { - typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; - }; - - template - struct lua_size : std::integral_constant { - typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; - }; - - template - struct lua_size> : std::integral_constant::value + lua_size::value> { }; - - template - struct lua_size> : std::integral_constant::value> { }; - - namespace detail { - template - struct void_ { typedef void type; }; - template - struct has_internal_marker_impl : std::false_type {}; - template - struct has_internal_marker_impl::type> : std::true_type {}; - - template - struct has_internal_marker : has_internal_marker_impl {}; - } - - template - struct is_lua_primitive : std::integral_constant>::value - || ((type::userdata == lua_type_of>::value) - && detail::has_internal_marker>>::value - && !detail::has_internal_marker>>::value) - || std::is_base_of>::value - || std::is_base_of>::value - || meta::is_specialization_of>::value - || meta::is_specialization_of>::value - > { }; - - template - struct is_lua_reference : std::integral_constant>::value - || std::is_base_of>::value - || meta::is_specialization_of>::value - > { }; - - template - struct is_lua_primitive : std::true_type {}; - template - struct is_lua_primitive> : std::true_type { }; - template - struct is_lua_primitive> : std::true_type { }; - template - struct is_lua_primitive> : is_lua_primitive { }; - template - struct is_lua_primitive> : std::true_type {}; - template <> - struct is_lua_primitive : std::true_type {}; - template <> - struct is_lua_primitive : std::true_type {}; - template - struct is_lua_primitive> : is_lua_primitive {}; - - template - struct is_proxy_primitive : is_lua_primitive { }; - - template - struct is_transparent_argument : std::false_type {}; - - template <> - struct is_transparent_argument : std::true_type {}; - - template <> - struct is_transparent_argument : std::true_type {}; - - template - struct is_variadic_arguments : std::is_same {}; - - template - struct lua_bind_traits : meta::bind_traits { - private: - typedef meta::bind_traits base_t; - public: - typedef std::integral_constant::value != 0> runtime_variadics_t; - static const std::size_t true_arity = base_t::arity; - static const std::size_t arity = base_t::arity - meta::count_for::value; - static const std::size_t true_free_arity = base_t::free_arity; - static const std::size_t free_arity = base_t::free_arity - meta::count_for::value; - }; - - template - struct is_table : std::false_type {}; - template - struct is_table> : std::true_type {}; - - template - struct is_function : std::false_type {}; - template - struct is_function> : std::true_type {}; - template - struct is_function> : std::true_type {}; - - template - struct is_lightuserdata : std::false_type {}; - template - struct is_lightuserdata> : std::true_type {}; - - template - struct is_userdata : std::false_type {}; - template - struct is_userdata> : std::true_type {}; - - template - struct is_environment : std::integral_constant::value || is_table::value> {}; - - template - struct is_container : detail::is_container{}; - - template - inline type type_of() { - return lua_type_of>::value; - } - - namespace detail { - template - struct lua_type_of, std::enable_if_t<::sol::is_container::value>> : std::integral_constant {}; - - template - struct lua_type_of, std::enable_if_t::value>> : lua_type_of {}; - } // detail -} // sol - -// end of sol/types.hpp - -// beginning of sol/stack_reference.hpp - -namespace sol { - class stack_reference { - private: - lua_State* L = nullptr; - int index = 0; - - protected: - int registry_index() const noexcept { - return LUA_NOREF; - } - - public: - stack_reference() noexcept = default; - stack_reference(lua_nil_t) noexcept : stack_reference() {}; - stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {} - stack_reference(lua_State* L, absolute_index i) noexcept : L(L), index(i) {} - stack_reference(lua_State* L, raw_index i) noexcept : L(L), index(i) {} - stack_reference(lua_State* L, ref_index i) noexcept = delete; - stack_reference(stack_reference&& o) noexcept = default; - stack_reference& operator=(stack_reference&&) noexcept = default; - stack_reference(const stack_reference&) noexcept = default; - stack_reference& operator=(const stack_reference&) noexcept = default; - - int push() const noexcept { - return push(lua_state()); - } - - int push(lua_State* Ls) const noexcept { - lua_pushvalue(lua_state(), index); - if (Ls != lua_state()) { - lua_xmove(lua_state(), Ls, 1); - } - return 1; - } - - void pop() const noexcept { - pop(lua_state()); - } - - void pop(lua_State* Ls, int n = 1) const noexcept { - lua_pop(Ls, n); - } - - int stack_index() const noexcept { - return index; - } - - type get_type() const noexcept { - int result = lua_type(L, index); - return static_cast(result); - } - - lua_State* lua_state() const noexcept { - return L; - } - - bool valid() const noexcept { - type t = get_type(); - return t != type::lua_nil && t != type::none; - } - }; - - inline bool operator== (const stack_reference& l, const stack_reference& r) { - return lua_compare(l.lua_state(), l.stack_index(), r.stack_index(), LUA_OPEQ) == 0; - } - - inline bool operator!= (const stack_reference& l, const stack_reference& r) { - return !operator==(l, r); - } - - inline bool operator==(const stack_reference& lhs, const lua_nil_t&) { - return !lhs.valid(); - } - - inline bool operator==(const lua_nil_t&, const stack_reference& rhs) { - return !rhs.valid(); - } - - inline bool operator!=(const stack_reference& lhs, const lua_nil_t&) { - return lhs.valid(); - } - - inline bool operator!=(const lua_nil_t&, const stack_reference& rhs) { - return rhs.valid(); - } -} // sol - -// end of sol/stack_reference.hpp - -namespace sol { - namespace stack { - inline void remove(lua_State* L, int rawindex, int count) { - if (count < 1) - return; - int top = lua_gettop(L); - if (rawindex == -count || top == rawindex) { - // Slice them right off the top - lua_pop(L, static_cast(count)); - return; - } - - // Remove each item one at a time using stack operations - // Probably slower, maybe, haven't benchmarked, - // but necessary - int index = lua_absindex(L, rawindex); - if (index < 0) { - index = lua_gettop(L) + (index + 1); - } - int last = index + count; - for (int i = index; i < last; ++i) { - lua_remove(L, index); - } - } - - struct push_popper_at { - lua_State* L; - int index; - int count; - push_popper_at(lua_State* luastate, int index = -1, int count = 1) : L(luastate), index(index), count(count) { } - ~push_popper_at() { remove(L, index, count); } - }; - - template - struct push_popper_n { - lua_State* L; - int t; - push_popper_n(lua_State* luastate, int x) : L(luastate), t(x) { } - ~push_popper_n() { lua_pop(L, t); } - }; - template <> - struct push_popper_n { - push_popper_n(lua_State*, int) { } - }; - template - struct push_popper { - T t; - push_popper(T x) : t(x) { t.push(); } - ~push_popper() { t.pop(); } - }; - template - struct push_popper { - push_popper(T) {} - ~push_popper() {} - }; - template - push_popper push_pop(T&& x) { - return push_popper(std::forward(x)); - } - template - push_popper_at push_pop_at(T&& x) { - int c = x.push(); - lua_State* L = x.lua_state(); - return push_popper_at(L, lua_absindex(L, -c), c); - } - template - push_popper_n pop_n(lua_State* L, int x) { - return push_popper_n(L, x); - } - } // stack - - namespace detail { - struct global_tag { } const global_{}; - struct no_safety_tag {} const no_safety{}; - } // detail - - class reference { - private: - lua_State* luastate = nullptr; // non-owning - int ref = LUA_NOREF; - - int copy() const noexcept { - if (ref == LUA_NOREF) - return LUA_NOREF; - push(); - return luaL_ref(lua_state(), LUA_REGISTRYINDEX); - } - - protected: - reference(lua_State* L, detail::global_tag) noexcept : luastate(L) { - lua_pushglobaltable(lua_state()); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); - } - - int stack_index() const noexcept { - return -1; - } - - void deref() const noexcept { - luaL_unref(lua_state(), LUA_REGISTRYINDEX, ref); - } - - public: - reference() noexcept = default; - reference(lua_nil_t) noexcept : reference() {} - reference(const stack_reference& r) noexcept : reference(r.lua_state(), r.stack_index()) {} - reference(stack_reference&& r) noexcept : reference(r.lua_state(), r.stack_index()) {} - reference(lua_State* L, int index = -1) noexcept : luastate(L) { - lua_pushvalue(lua_state(), index); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); - } - reference(lua_State* L, ref_index index) noexcept : luastate(L) { - lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); - } - - ~reference() noexcept { - deref(); - } - - reference(reference&& o) noexcept { - luastate = o.luastate; - ref = o.ref; - - o.luastate = nullptr; - o.ref = LUA_NOREF; - } - - reference& operator=(reference&& o) noexcept { - if (valid()) { - deref(); - } - luastate = o.luastate; - ref = o.ref; - - o.luastate = nullptr; - o.ref = LUA_NOREF; - - return *this; - } - - reference(const reference& o) noexcept { - luastate = o.luastate; - ref = o.copy(); - } - - reference& operator=(const reference& o) noexcept { - luastate = o.luastate; - deref(); - ref = o.copy(); - return *this; - } - - int push() const noexcept { - return push(lua_state()); - } - - int push(lua_State* Ls) const noexcept { - lua_rawgeti(Ls, LUA_REGISTRYINDEX, ref); - return 1; - } - - void pop() const noexcept { - pop(lua_state()); - } - - void pop(lua_State* Ls, int n = 1) const noexcept { - lua_pop(Ls, n); - } - - int registry_index() const noexcept { - return ref; - } - - bool valid() const noexcept { - return !(ref == LUA_NOREF || ref == LUA_REFNIL); - } - - explicit operator bool() const noexcept { - return valid(); - } - - type get_type() const noexcept { - auto pp = stack::push_pop(*this); - int result = lua_type(lua_state(), -1); - return static_cast(result); - } - - lua_State* lua_state() const noexcept { - return luastate; - } - }; - - inline bool operator== (const reference& l, const reference& r) { - auto ppl = stack::push_pop(l); - auto ppr = stack::push_pop(r); - return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1; - } - - inline bool operator!= (const reference& l, const reference& r) { - return !operator==(l, r); - } - - inline bool operator==(const reference& lhs, const lua_nil_t&) { - return !lhs.valid(); - } - - inline bool operator==(const lua_nil_t&, const reference& rhs) { - return !rhs.valid(); - } - - inline bool operator!=(const reference& lhs, const lua_nil_t&) { - return lhs.valid(); - } - - inline bool operator!=(const lua_nil_t&, const reference& rhs) { - return rhs.valid(); - } -} // sol - -// end of sol/reference.hpp - -// beginning of sol/stack.hpp - -// beginning of sol/stack_core.hpp - -// beginning of sol/tie.hpp - -namespace sol { - - namespace detail { - template - struct is_speshul : std::false_type {}; - } - - template - struct tie_size : std::tuple_size {}; - - template - struct is_tieable : std::integral_constant::value > 0)> {}; - - template - struct tie_t : public std::tuple...> { - private: - typedef std::tuple...> base_t; - - template - void set(std::false_type, T&& target) { - std::get<0>(*this) = std::forward(target); - } - - template - void set(std::true_type, T&& target) { - typedef tie_size> value_size; - typedef tie_size> tie_size; - typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size; - typedef std::make_index_sequence indices; - set_extra(detail::is_speshul>(), indices(), std::forward(target)); - } - - template - void set_extra(std::true_type, std::index_sequence, T&& target) { - using std::get; - (void)detail::swallow{ 0, - (get(static_cast(*this)) = get(types(), target), 0)... - , 0 }; - } - - template - void set_extra(std::false_type, std::index_sequence, T&& target) { - using std::get; - (void)detail::swallow{ 0, - (get(static_cast(*this)) = get(target), 0)... - , 0 }; - } - - public: - using base_t::base_t; - - template - tie_t& operator= (T&& value) { - typedef is_tieable> tieable; - set(tieable(), std::forward(value)); - return *this; - } - - }; - - template - struct tie_size< tie_t > : std::tuple_size< std::tuple > { }; - - namespace adl_barrier_detail { - template - inline tie_t...> tie(Tn&&... argn) { - return tie_t...>(std::forward(argn)...); - } - } - - using namespace adl_barrier_detail; - -} // sol - -// end of sol/tie.hpp - -// beginning of sol/stack_guard.hpp - -namespace sol { - namespace detail { - inline void stack_fail(int, int) { -#ifndef SOL_NO_EXCEPTIONS - throw error(detail::direct_error, "imbalanced stack after operation finish"); -#else - // Lol, what do you want, an error printout? :3c - // There's no sane default here. The right way would be C-style abort(), and that's not acceptable, so - // hopefully someone will register their own stack_fail thing for the `fx` parameter of stack_guard. -#endif // No Exceptions - } - } // detail - - struct stack_guard { - lua_State* L; - int top; - std::function on_mismatch; - - stack_guard(lua_State* L) : stack_guard(L, lua_gettop(L)) {} - stack_guard(lua_State* L, int top, std::function fx = detail::stack_fail) : L(L), top(top), on_mismatch(std::move(fx)) {} - bool check_stack(int modification = 0) const { - int bottom = lua_gettop(L) + modification; - if (top == bottom) { - return true; - } - on_mismatch(top, bottom); - return false; - } - ~stack_guard() { - check_stack(); - } - }; -} // sol - -// end of sol/stack_guard.hpp - -#include - -namespace sol { - namespace detail { - struct as_reference_tag {}; - template - struct as_pointer_tag {}; - template - struct as_value_tag {}; - - using special_destruct_func = void(*)(void*); - - template - inline void special_destruct(void* memory) { - T** pointerpointer = static_cast(memory); - special_destruct_func* dx = static_cast(static_cast(pointerpointer + 1)); - Real* target = static_cast(static_cast(dx + 1)); - target->~Real(); - } - - template - inline int unique_destruct(lua_State* L) { - void* memory = lua_touserdata(L, 1); - T** pointerpointer = static_cast(memory); - special_destruct_func& dx = *static_cast(static_cast(pointerpointer + 1)); - (dx)(memory); - return 0; - } - - template - inline int user_alloc_destroy(lua_State* L) { - void* rawdata = lua_touserdata(L, 1); - T* data = static_cast(rawdata); - std::allocator alloc; - alloc.destroy(data); - return 0; - } - - template - inline int usertype_alloc_destroy(lua_State* L) { - void* rawdata = lua_touserdata(L, 1); - T** pdata = static_cast(rawdata); - T* data = *pdata; - std::allocator alloc{}; - alloc.destroy(data); - return 0; - } - - template - void reserve(T&, std::size_t) {} - - template - void reserve(std::vector& arr, std::size_t hint) { - arr.reserve(hint); - } - - template - void reserve(std::basic_string& arr, std::size_t hint) { - arr.reserve(hint); - } - } // detail - - namespace stack { - - template - struct field_getter; - template - struct probe_field_getter; - template - struct field_setter; - template - struct getter; - template - struct popper; - template - struct pusher; - template::value, typename = void> - struct checker; - template - struct check_getter; - - struct probe { - bool success; - int levels; - - probe(bool s, int l) : success(s), levels(l) {} - - operator bool() const { return success; }; - }; - - struct record { - int last; - int used; - - record() : last(), used() {} - void use(int count) { - last = count; - used += count; - } - }; - - namespace stack_detail { - template - struct strip { - typedef T type; - }; - template - struct strip> { - typedef T& type; - }; - template - struct strip> { - typedef T& type; - }; - template - struct strip> { - typedef T type; - }; - template - using strip_t = typename strip::type; - const bool default_check_arguments = -#ifdef SOL_CHECK_ARGUMENTS - true; -#else - false; -#endif - template - inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { - return getter>{}.get(L, index, tracking); - } - } // stack_detail - - inline bool maybe_indexable(lua_State* L, int index = -1) { - type t = type_of(L, index); - return t == type::userdata || t == type::table; - } - - template - inline int push(lua_State* L, T&& t, Args&&... args) { - return pusher>{}.push(L, std::forward(t), std::forward(args)...); - } - - // overload allows to use a pusher of a specific type, but pass in any kind of args - template::value>> - inline int push(lua_State* L, Arg&& arg, Args&&... args) { - return pusher>{}.push(L, std::forward(arg), std::forward(args)...); - } - - template - inline int push_reference(lua_State* L, T&& t, Args&&... args) { - typedef meta::all< - std::is_lvalue_reference, - meta::neg>, - meta::neg>>, - meta::neg>> - > use_reference_tag; - return pusher>>{}.push(L, std::forward(t), std::forward(args)...); - } - - inline int multi_push(lua_State*) { - // do nothing - return 0; - } - - template - inline int multi_push(lua_State* L, T&& t, Args&&... args) { - int pushcount = push(L, std::forward(t)); - void(sol::detail::swallow{ (pushcount += sol::stack::push(L, std::forward(args)), 0)... }); - return pushcount; - } - - inline int multi_push_reference(lua_State*) { - // do nothing - return 0; - } - - template - inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) { - int pushcount = push_reference(L, std::forward(t)); - void(sol::detail::swallow{ (pushcount += sol::stack::push_reference(L, std::forward(args)), 0)... }); - return pushcount; - } - - template - bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - typedef meta::unqualified_t Tu; - checker c; - // VC++ has a bad warning here: shut it up - (void)c; - return c.check(L, index, std::forward(handler), tracking); - } - - template - bool check(lua_State* L, int index, Handler&& handler) { - record tracking{}; - return check(L, index, std::forward(handler), tracking); - } - - template - bool check(lua_State* L, int index = -lua_size>::value) { - auto handler = no_panic; - return check(L, index, handler); - } - - template - inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) { - return check_getter>{}.get(L, index, std::forward(handler), tracking); - } - - template - inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) { - record tracking{}; - return check_get(L, index, handler, tracking); - } - - template - inline decltype(auto) check_get(lua_State* L, int index = -lua_size>::value) { - auto handler = no_panic; - return check_get(L, index, handler); - } - - namespace stack_detail { - -#ifdef SOL_CHECK_ARGUMENTS - template - inline auto tagged_get(types, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get(L, index, tracking)) { - auto op = check_get(L, index, type_panic, tracking); - return *std::move(op); - } -#else - template - inline decltype(auto) tagged_get(types, lua_State* L, int index, record& tracking) { - return stack_detail::unchecked_get(L, index, tracking); - } -#endif - - template - inline decltype(auto) tagged_get(types>, lua_State* L, int index, record& tracking) { - return stack_detail::unchecked_get>(L, index, tracking); - } - - template - struct check_types { - template - static bool check(types, lua_State* L, int firstargument, Handler&& handler, record& tracking) { - if (!stack::check(L, firstargument + tracking.used, handler, tracking)) - return false; - return check(types(), L, firstargument, std::forward(handler), tracking); - } - - template - static bool check(types<>, lua_State*, int, Handler&&, record&) { - return true; - } - }; - - template <> - struct check_types { - template - static bool check(types, lua_State*, int, Handler&&, record&) { - return true; - } - }; - - } // stack_detail - - template - bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack_detail::check_types{}.check(types...>(), L, index, std::forward(handler), tracking); - } - - template - bool multi_check(lua_State* L, int index, Handler&& handler) { - record tracking{}; - return multi_check(L, index, std::forward(handler), tracking); - } - - template - bool multi_check(lua_State* L, int index) { - auto handler = no_panic; - return multi_check(L, index, handler); - } - - template - bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) { - return multi_check(L, index, std::forward(handler), tracking); - } - - template - bool multi_check(lua_State* L, int index, Handler&& handler) { - return multi_check(L, index, std::forward(handler)); - } - - template - bool multi_check(lua_State* L, int index) { - return multi_check(L, index); - } - - template - inline decltype(auto) get(lua_State* L, int index, record& tracking) { - return stack_detail::tagged_get(types(), L, index, tracking); - } - - template - inline decltype(auto) get(lua_State* L, int index = -lua_size>::value) { - record tracking{}; - return get(L, index, tracking); - } - - template - inline decltype(auto) pop(lua_State* L) { - return popper>{}.pop(L); - } - - template - void get_field(lua_State* L, Key&& key) { - field_getter, global, raw>{}.get(L, std::forward(key)); - } - - template - void get_field(lua_State* L, Key&& key, int tableindex) { - field_getter, global, raw>{}.get(L, std::forward(key), tableindex); - } - - template - void raw_get_field(lua_State* L, Key&& key) { - get_field(L, std::forward(key)); - } - - template - void raw_get_field(lua_State* L, Key&& key, int tableindex) { - get_field(L, std::forward(key), tableindex); - } - - template - probe probe_get_field(lua_State* L, Key&& key) { - return probe_field_getter, global, raw>{}.get(L, std::forward(key)); - } - - template - probe probe_get_field(lua_State* L, Key&& key, int tableindex) { - return probe_field_getter, global, raw>{}.get(L, std::forward(key), tableindex); - } - - template - probe probe_raw_get_field(lua_State* L, Key&& key) { - return probe_get_field(L, std::forward(key)); - } - - template - probe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) { - return probe_get_field(L, std::forward(key), tableindex); - } - - template - void set_field(lua_State* L, Key&& key, Value&& value) { - field_setter, global, raw>{}.set(L, std::forward(key), std::forward(value)); - } - - template - void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { - field_setter, global, raw>{}.set(L, std::forward(key), std::forward(value), tableindex); - } - - template - void raw_set_field(lua_State* L, Key&& key, Value&& value) { - set_field(L, std::forward(key), std::forward(value)); - } - - template - void raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) { - set_field(L, std::forward(key), std::forward(value), tableindex); - } - } // stack -} // sol - -// end of sol/stack_core.hpp - -// beginning of sol/stack_check.hpp - -// beginning of sol/usertype_traits.hpp - -// beginning of sol/demangle.hpp - -#include -#include - -namespace sol { - namespace detail { -#if defined(__GNUC__) || defined(__clang__) - template - inline std::string ctti_get_type_name() { - const static std::array removals = { { "{anonymous}", "(anonymous namespace)" } }; - std::string name = __PRETTY_FUNCTION__; - std::size_t start = name.find_first_of('['); - start = name.find_first_of('=', start); - std::size_t end = name.find_last_of(']'); - if (end == std::string::npos) - end = name.size(); - if (start == std::string::npos) - start = 0; - if (start < name.size() - 1) - start += 1; - name = name.substr(start, end - start); - start = name.rfind("seperator_mark"); - if (start != std::string::npos) { - name.erase(start - 2, name.length()); - } - while (!name.empty() && std::isblank(name.front())) name.erase(name.begin()); - while (!name.empty() && std::isblank(name.back())) name.pop_back(); - - for (std::size_t r = 0; r < removals.size(); ++r) { - auto found = name.find(removals[r]); - while (found != std::string::npos) { - name.erase(found, removals[r].size()); - found = name.find(removals[r]); - } - } - - return name; - } -#elif defined(_MSC_VER) - template - inline std::string ctti_get_type_name() { - const static std::array removals = { { "public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'" } }; - std::string name = __FUNCSIG__; - std::size_t start = name.find("get_type_name"); - if (start == std::string::npos) - start = 0; - else - start += 13; - if (start < name.size() - 1) - start += 1; - std::size_t end = name.find_last_of('>'); - if (end == std::string::npos) - end = name.size(); - name = name.substr(start, end - start); - if (name.find("struct", 0) == 0) - name.replace(0, 6, "", 0); - if (name.find("class", 0) == 0) - name.replace(0, 5, "", 0); - while (!name.empty() && std::isblank(name.front())) name.erase(name.begin()); - while (!name.empty() && std::isblank(name.back())) name.pop_back(); - - for (std::size_t r = 0; r < removals.size(); ++r) { - auto found = name.find(removals[r]); - while (found != std::string::npos) { - name.erase(found, removals[r].size()); - found = name.find(removals[r]); - } - } - - return name; - } -#else -#error Compiler not supported for demangling -#endif // compilers - - template - inline std::string demangle_once() { - std::string realname = ctti_get_type_name(); - return realname; - } - - template - inline std::string short_demangle_once() { - std::string realname = ctti_get_type_name(); - // This isn't the most complete but it'll do for now...? - static const std::array ops = { { "operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*" } }; - int level = 0; - std::ptrdiff_t idx = 0; - for (idx = static_cast(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) { - if (level == 0 && realname[idx] == ':') { - break; - } - bool isleft = realname[idx] == '<'; - bool isright = realname[idx] == '>'; - if (!isleft && !isright) - continue; - bool earlybreak = false; - for (const auto& op : ops) { - std::size_t nisop = realname.rfind(op, idx); - if (nisop == std::string::npos) - continue; - std::size_t nisopidx = idx - op.size() + 1; - if (nisop == nisopidx) { - idx = static_cast(nisopidx); - earlybreak = true; - } - break; - } - if (earlybreak) { - continue; - } - level += isleft ? -1 : 1; - } - if (idx > 0) { - realname.erase(0, realname.length() < static_cast(idx) ? realname.length() : idx + 1); - } - return realname; - } - - template - inline const std::string& demangle() { - static const std::string d = demangle_once(); - return d; - } - - template - inline const std::string& short_demangle() { - static const std::string d = short_demangle_once(); - return d; - } - } // detail -} // sol - -// end of sol/demangle.hpp - -namespace sol { - - template - struct usertype_traits { - static const std::string& name() { - static const std::string& n = detail::short_demangle(); - return n; - } - static const std::string& qualified_name() { - static const std::string& q_n = detail::demangle(); - return q_n; - } - static const std::string& metatable() { - static const std::string m = std::string("sol.").append(detail::demangle()); - return m; - } - static const std::string& user_metatable() { - static const std::string u_m = std::string("sol.").append(detail::demangle()).append(".user"); - return u_m; - } - static const std::string& user_gc_metatable() { - static const std::string u_g_m = std::string("sol.").append(detail::demangle()).append(".user\xE2\x99\xBB"); - return u_g_m; - } - static const std::string& gc_table() { - static const std::string g_t = std::string("sol.").append(detail::demangle()).append(".\xE2\x99\xBB"); - return g_t; - } - }; - -} - -// end of sol/usertype_traits.hpp - -// beginning of sol/inheritance.hpp - -#include - -namespace sol { - template - struct base_list { }; - template - using bases = base_list; - - typedef bases<> base_classes_tag; - const auto base_classes = base_classes_tag(); - - namespace detail { - - template - struct has_derived { - static bool value; - }; - - template - bool has_derived::value = false; - - inline std::size_t unique_id() { - static std::atomic x(0); - return ++x; - } - - template - struct id_for { - static const std::size_t value; - }; - - template - const std::size_t id_for::value = unique_id(); - - inline decltype(auto) base_class_check_key() { - static const auto& key = "class_check"; - return key; - } - - inline decltype(auto) base_class_cast_key() { - static const auto& key = "class_cast"; - return key; - } - - inline decltype(auto) base_class_index_propogation_key() { - static const auto& key = u8"\xF0\x9F\x8C\xB2.index"; - return key; - } - - inline decltype(auto) base_class_new_index_propogation_key() { - static const auto& key = u8"\xF0\x9F\x8C\xB2.new_index"; - return key; - } - - template - struct inheritance { - static bool type_check_bases(types<>, std::size_t) { - return false; - } - - template - static bool type_check_bases(types, std::size_t ti) { - return ti == id_for::value || type_check_bases(types(), ti); - } - - static bool type_check(std::size_t ti) { - return ti == id_for::value || type_check_bases(types(), ti); - } - - static void* type_cast_bases(types<>, T*, std::size_t) { - return nullptr; - } - - template - static void* type_cast_bases(types, T* data, std::size_t ti) { - // Make sure to convert to T first, and then dynamic cast to the proper type - return ti != id_for::value ? type_cast_bases(types(), data, ti) : static_cast(static_cast(data)); - } - - static void* type_cast(void* voiddata, std::size_t ti) { - T* data = static_cast(voiddata); - return static_cast(ti != id_for::value ? type_cast_bases(types(), data, ti) : data); - } - }; - - using inheritance_check_function = decltype(&inheritance::type_check); - using inheritance_cast_function = decltype(&inheritance::type_cast); - - } // detail -} // sol - -// end of sol/inheritance.hpp - -#include - -namespace sol { - namespace stack { - namespace stack_detail { - template - inline bool check_metatable(lua_State* L, int index = -2) { - const auto& metakey = usertype_traits::metatable(); - luaL_getmetatable(L, &metakey[0]); - const type expectedmetatabletype = static_cast(lua_type(L, -1)); - if (expectedmetatabletype != type::lua_nil) { - if (lua_rawequal(L, -1, index) == 1) { - lua_pop(L, 1 + static_cast(poptable)); - return true; - } - } - lua_pop(L, 1); - return false; - } - - template - struct basic_check { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - bool success = check_func(L, index) == 1; - if (!success) { - // expected type, actual type - handler(L, index, expected, type_of(L, index)); - } - return success; - } - }; - } // stack_detail - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - const type indextype = type_of(L, index); - bool success = expected == indextype; - if (!success) { - // expected type, actual type - handler(L, index, expected, indextype); - } - return success; - } - }; - - template - struct checker::value>> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - bool success = lua_isinteger(L, index) == 1; - if (!success) { - // expected type, actual type - handler(L, index, type::number, type_of(L, index)); - } - return success; - } - }; - - template - struct checker::value>> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - bool success = lua_isnumber(L, index) == 1; - if (!success) { - // expected type, actual type - handler(L, index, type::number, type_of(L, index)); - } - return success; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - bool success = lua_isnil(L, index); - if (success) { - tracking.use(1); - return success; - } - tracking.use(0); - success = lua_isnone(L, index); - if (!success) { - // expected type, actual type - handler(L, index, expected, type_of(L, index)); - } - return success; - } - }; - - template - struct checker : checker {}; - - template - struct checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - bool success = !lua_isnone(L, index); - if (!success) { - // expected type, actual type - handler(L, index, type::none, type_of(L, index)); - } - return success; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - bool success = t == type::userdata || t == type::lightuserdata; - if (!success) { - // expected type, actual type - handler(L, index, type::lightuserdata, t); - } - return success; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - bool success = t == type::userdata; - if (!success) { - // expected type, actual type - handler(L, index, type::userdata, t); - } - return success; - } - }; - - template - struct checker, type::userdata, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::check(L, index, std::forward(handler), tracking); - } - }; - - template - struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; - - template - struct checker, type::userdata, C> : checker::value, C> {}; - - template - struct checker : stack_detail::basic_check {}; - template - struct checker, type::function, C> : checker {}; - template - struct checker : checker {}; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - if (t == type::lua_nil || t == type::none || t == type::function) { - // allow for lua_nil to be returned - return true; - } - if (t != type::userdata && t != type::table) { - handler(L, index, type::function, t); - return false; - } - // Do advanced check for call-style userdata? - static const auto& callkey = to_string(meta_function::call); - if (lua_getmetatable(L, index) == 0) { - // No metatable, no __call key possible - handler(L, index, type::function, t); - return false; - } - if (lua_isnoneornil(L, -1)) { - lua_pop(L, 1); - handler(L, index, type::function, t); - return false; - } - lua_getfield(L, -1, &callkey[0]); - if (lua_isnoneornil(L, -1)) { - lua_pop(L, 2); - handler(L, index, type::function, t); - return false; - } - // has call, is definitely a function - lua_pop(L, 2); - return true; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - if (t == type::table) { - return true; - } - if (t != type::userdata) { - handler(L, index, type::table, t); - return false; - } - return true; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - if (lua_getmetatable(L, index) == 0) { - return true; - } - type t = type_of(L, -1); - if (t == type::table || t == type::none || t == type::nil) { - lua_pop(L, 1); - return true; - } - if (t != type::userdata) { - lua_pop(L, 1); - handler(L, index, expected, t); - return false; - } - return true; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - if (lua_getmetatable(L, index) == 0) { - return true; - } - type t = type_of(L, -1); - if (t == type::table || t == type::none || t == type::nil) { - lua_pop(L, 1); - return true; - } - if (t != type::userdata) { - lua_pop(L, 1); - handler(L, index, type::table, t); - return false; - } - return true; - } - }; - - template - struct checker, type::poly, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - if (lua_getmetatable(L, index) == 0) { - return true; - } - type t = type_of(L, -1); - if (t == type::table || t == type::none || t == type::nil) { - lua_pop(L, 1); - return true; - } - if (t != type::userdata) { - lua_pop(L, 1); - handler(L, index, type::table, t); - return false; - } - return true; - } - }; - - template - struct checker, type::userdata, C> { - template - static bool check(types, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) { - tracking.use(1); - if (indextype != type::userdata) { - handler(L, index, type::userdata, indextype); - return false; - } - if (meta::any, std::is_same, std::is_same, std::is_same>::value) - return true; - if (lua_getmetatable(L, index) == 0) { - return true; - } - int metatableindex = lua_gettop(L); - if (stack_detail::check_metatable(L, metatableindex)) - return true; - if (stack_detail::check_metatable(L, metatableindex)) - return true; - if (stack_detail::check_metatable>(L, metatableindex)) - return true; - bool success = false; - if (detail::has_derived::value) { - auto pn = stack::pop_n(L, 1); - lua_pushstring(L, &detail::base_class_check_key()[0]); - lua_rawget(L, metatableindex); - if (type_of(L, -1) != type::lua_nil) { - void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; - success = ic(detail::id_for::value); - } - } - if (!success) { - lua_pop(L, 1); - handler(L, index, type::userdata, indextype); - return false; - } - lua_pop(L, 1); - return true; - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - return checker, type::userdata, C>{}.check(types(), L, indextype, index, std::forward(handler), tracking); - } - }; - - template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - // Allow lua_nil to be transformed to nullptr - if (indextype == type::lua_nil) { - tracking.use(1); - return true; - } - return checker, type::userdata, C>{}.check(L, index, std::forward(handler), tracking); - } - }; - - template - struct checker::value>> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return checker::type, type::userdata>{}.check(L, index, std::forward(handler), tracking); - } - }; - - template - struct checker, type::userdata, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return checker{}.check(L, index, std::forward(handler), tracking); - } - }; - - template - struct checker, type::poly, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::multi_check(L, index, std::forward(handler), tracking); - } - }; - - template - struct checker, type::poly, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::multi_check(L, index, std::forward(handler), tracking); - } - }; - - template - struct checker, type::poly, C> { - template - static bool check(lua_State* L, int index, Handler&&, record& tracking) { - type t = type_of(L, index); - if (t == type::none) { - tracking.use(0); - return true; - } - if (t == type::lua_nil) { - tracking.use(1); - return true; - } - return stack::check(L, index, no_panic, tracking); - } - }; - } // stack -} // sol - -// end of sol/stack_check.hpp - -// beginning of sol/stack_get.hpp - -// beginning of sol/overload.hpp - -namespace sol { - template - struct overload_set { - std::tuple functions; - template >> = meta::enabler> - overload_set (Arg&& arg, Args&&... args) : functions(std::forward(arg), std::forward(args)...) {} - overload_set(const overload_set&) = default; - overload_set(overload_set&&) = default; - overload_set& operator=(const overload_set&) = default; - overload_set& operator=(overload_set&&) = default; - }; - - template - decltype(auto) overload(Args&&... args) { - return overload_set...>(std::forward(args)...); - } -} - -// end of sol/overload.hpp - -#ifdef SOL_CODECVT_SUPPORT -#include -#endif - -namespace sol { - namespace stack { - - template - struct getter { - static T& get(lua_State* L, int index, record& tracking) { - return getter>{}.get(L, index, tracking); - } - }; - - template - struct getter::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_tonumber(L, index)); - } - }; - - template - struct getter, std::is_signed>::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_tointeger(L, index)); - } - }; - - template - struct getter, std::is_unsigned>::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_tointeger(L, index)); - } - }; - - template - struct getter::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_tointegerx(L, index, nullptr)); - } - }; - - template - struct getter, std::enable_if_t>::value>> { - static T get(lua_State* L, int relindex, record& tracking) { - typedef typename T::value_type V; - return get(types(), L, relindex, tracking); - } - - template - static T get(types, lua_State* L, int relindex, record& tracking) { - tracking.use(1); - - int index = lua_absindex(L, relindex); - T arr; -#if SOL_LUA_VERSION >= 503 - // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 - for (lua_Integer i = 0; ; i += lua_size::value, lua_pop(L, lua_size::value)) { - bool isnil = false; - for (int vi = 0; vi < lua_size::value; ++vi) { - type t = static_cast(lua_geti(L, index, i + vi)); - isnil = t == type::lua_nil; - if (isnil) { - if (i == 0) { - break; - } - lua_pop(L, (vi + 1)); - return arr; - } - } - if (isnil) - continue; - arr.push_back(stack::get(L, -lua_size::value)); - } -#else - // Zzzz slower but necessary thanks to the lower version API and missing functions qq - for (lua_Integer i = 0; ; i += lua_size::value, lua_pop(L, lua_size::value)) { - bool isnil = false; - for (int vi = 0; vi < lua_size::value; ++vi) { - lua_pushinteger(L, i); - lua_gettable(L, index); - type t = type_of(L, -1); - isnil = t == type::lua_nil; - if (isnil) { - if (i == 0) { - break; - } - lua_pop(L, (vi + 1)); - return arr; - } - } - if (isnil) - continue; - arr.push_back(stack::get(L, -1)); - } -#endif - return arr; - } - }; - - template - struct getter, std::enable_if_t>::value>> { - static T get(lua_State* L, int index, record& tracking) { - typedef typename T::value_type P; - typedef typename P::first_type K; - typedef typename P::second_type V; - return get(types(), L, index, tracking); - } - - template - static T get(types, lua_State* L, int relindex, record& tracking) { - tracking.use(1); - - T associative; - int index = lua_absindex(L, relindex); - lua_pushnil(L); - while (lua_next(L, index) != 0) { - decltype(auto) key = stack::check_get(L, -2); - if (!key) { - lua_pop(L, 1); - continue; - } - associative.emplace(std::forward(*key), stack::get(L, -1)); - lua_pop(L, 1); - } - return associative; - } - }; - - template - struct getter, std::enable_if_t::value>> { - static T get(lua_State* L, int index, record& tracking) { - getter g; - // VC++ has a bad warning here: shut it up - (void)g; - return g.get(L, index, tracking); - } - }; - - template - struct getter, std::enable_if_t, meta::neg>>>::value>> { - static T get(lua_State* L, int index, record& tracking) { - typedef typename T::value_type V; - getter> g; - // VC++ has a bad warning here: shut it up - (void)g; - return g.get(types>(), L, index, tracking); - } - }; - - template - struct getter, std::enable_if_t, meta::has_key_value_pair>>::value>> { - static T get(lua_State* L, int index, record& tracking) { - typedef typename T::value_type P; - typedef typename P::first_type K; - typedef typename P::second_type V; - getter> g; - // VC++ has a bad warning here: shut it up - (void)g; - return g.get(types>(), L, index, tracking); - } - }; - - template - struct getter::value || std::is_base_of::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return T(L, index); - } - }; - - template<> - struct getter { - static userdata_value get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return userdata_value(lua_touserdata(L, index)); - } - }; - - template<> - struct getter { - static lightuserdata_value get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return lightuserdata_value(lua_touserdata(L, index)); - } - }; - - template - struct getter> { - static light get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return light(static_cast(lua_touserdata(L, index))); - } - }; - - template - struct getter> { - static T& get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return *static_cast(lua_touserdata(L, index)); - } - }; - - template - struct getter> { - static T* get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_touserdata(L, index)); - } - }; - - template<> - struct getter { - static type get(lua_State *L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_type(L, index)); - } - }; - - template<> - struct getter { - static bool get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return lua_toboolean(L, index) != 0; - } - }; - - template<> - struct getter { - static std::string get(lua_State* L, int index, record& tracking) { - tracking.use(1); - std::size_t len; - auto str = lua_tolstring(L, index, &len); - return std::string( str, len ); - } - }; - - template <> - struct getter { - string_detail::string_shim get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t len; - const char* p = lua_tolstring(L, index, &len); - return string_detail::string_shim(p, len); - } - }; - - template<> - struct getter { - static const char* get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return lua_tostring(L, index); - } - }; - - template<> - struct getter { - static char get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t len; - auto str = lua_tolstring(L, index, &len); - return len > 0 ? str[0] : '\0'; - } - }; - -#ifdef SOL_CODECVT_SUPPORT - template<> - struct getter { - static std::wstring get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t len; - auto str = lua_tolstring(L, index, &len); - if (len < 1) - return std::wstring(); - if (sizeof(wchar_t) == 2) { - static std::wstring_convert> convert; - std::wstring r = convert.from_bytes(str, str + len); -#ifdef __MINGW32__ - // Fuck you, MinGW, and fuck you libstdc++ for introducing this absolutely asinine bug - // https://sourceforge.net/p/mingw-w64/bugs/538/ - // http://chat.stackoverflow.com/transcript/message/32271369#32271369 - for (auto& c : r) { - uint8_t* b = reinterpret_cast(&c); - std::swap(b[0], b[1]); - } -#endif - return r; - } - static std::wstring_convert> convert; - std::wstring r = convert.from_bytes(str, str + len); - return r; - } - }; - - template<> - struct getter { - static std::u16string get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t len; - auto str = lua_tolstring(L, index, &len); - if (len < 1) - return std::u16string(); -#ifdef _MSC_VER - static std::wstring_convert, int16_t> convert; - auto intd = convert.from_bytes(str, str + len); - std::u16string r(intd.size(), '\0'); - std::memcpy(&r[0], intd.data(), intd.size() * sizeof(char16_t)); -#else - static std::wstring_convert, char16_t> convert; - std::u16string r = convert.from_bytes(str, str + len); -#endif // VC++ is a shit - return r; - } - }; - - template<> - struct getter { - static std::u32string get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t len; - auto str = lua_tolstring(L, index, &len); - if (len < 1) - return std::u32string(); -#ifdef _MSC_VER - static std::wstring_convert, int32_t> convert; - auto intd = convert.from_bytes(str, str + len); - std::u32string r(intd.size(), '\0'); - std::memcpy(&r[0], intd.data(), r.size() * sizeof(char32_t)); -#else - static std::wstring_convert, char32_t> convert; - std::u32string r = convert.from_bytes(str, str + len); -#endif // VC++ is a shit - return r; - } - }; - - template<> - struct getter { - static wchar_t get(lua_State* L, int index, record& tracking) { - auto str = getter{}.get(L, index, tracking); - return str.size() > 0 ? str[0] : wchar_t(0); - } - }; - - template<> - struct getter { - static char16_t get(lua_State* L, int index, record& tracking) { - auto str = getter{}.get(L, index, tracking); - return str.size() > 0 ? str[0] : char16_t(0); - } - }; - - template<> - struct getter { - static char32_t get(lua_State* L, int index, record& tracking) { - auto str = getter{}.get(L, index, tracking); - return str.size() > 0 ? str[0] : char32_t(0); - } - }; -#endif // codecvt header support - - template<> - struct getter { - static meta_function get(lua_State *L, int index, record& tracking) { - tracking.use(1); - const char* name = getter{}.get(L, index, tracking); - const auto& mfnames = meta_function_names(); - for (std::size_t i = 0; i < mfnames.size(); ++i) - if (mfnames[i] == name) - return static_cast(i); - return meta_function::construct; - } - }; - - template<> - struct getter { - static lua_nil_t get(lua_State*, int, record& tracking) { - tracking.use(1); - return lua_nil; - } - }; - - template<> - struct getter { - static std::nullptr_t get(lua_State*, int, record& tracking) { - tracking.use(1); - return nullptr; - } - }; - - template<> - struct getter { - static nullopt_t get(lua_State*, int, record& tracking) { - tracking.use(1); - return nullopt; - } - }; - - template<> - struct getter { - static this_state get(lua_State* L, int, record& tracking) { - tracking.use(0); - return this_state{ L }; - } - }; - - template<> - struct getter { - static lua_CFunction get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return lua_tocfunction(L, index); - } - }; - - template<> - struct getter { - static c_closure get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return c_closure(lua_tocfunction(L, index), -1); - } - }; - - template<> - struct getter { - static error get(lua_State* L, int index, record& tracking) { - tracking.use(1); - size_t sz = 0; - const char* err = lua_tolstring(L, index, &sz); - if (err == nullptr) { - return error(detail::direct_error, ""); - } - return error(detail::direct_error, std::string(err, sz)); - } - }; - - template<> - struct getter { - static void* get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return lua_touserdata(L, index); - } - }; - - template - struct getter> { - static T* get_no_lua_nil(lua_State* L, int index, record& tracking) { - tracking.use(1); - void** pudata = static_cast(lua_touserdata(L, index)); - void* udata = *pudata; - return get_no_lua_nil_from(L, udata, index, tracking); - } - - static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) { - if (detail::has_derived::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) { - void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata; - // use the casting function to properly adjust the pointer for the desired T - udata = ic(udata, detail::id_for::value); - lua_pop(L, 1); - } - T* obj = static_cast(udata); - return obj; - } - - static T& get(lua_State* L, int index, record& tracking) { - return *get_no_lua_nil(L, index, tracking); - } - }; - - template - struct getter> { - static T* get(lua_State* L, int index, record& tracking) { - type t = type_of(L, index); - if (t == type::lua_nil) { - tracking.use(1); - return nullptr; - } - getter> g; - // Avoid VC++ warning - (void)g; - return g.get_no_lua_nil(L, index, tracking); - } - }; - - template - struct getter> { - static T* get(lua_State* L, int index, record& tracking) { - getter> g; - // Avoid VC++ warning - (void)g; - return g.get_no_lua_nil(L, index, tracking); - } - }; - - template - struct getter { - static T& get(lua_State* L, int index, record& tracking) { - getter> g; - // Avoid VC++ warning - (void)g; - return g.get(L, index, tracking); - } - }; - - template - struct getter> { - static T& get(lua_State* L, int index, record& tracking) { - getter g; - // Avoid VC++ warning - (void)g; - return g.get(L, index, tracking); - } - }; - - template - struct getter { - static T* get(lua_State* L, int index, record& tracking) { - getter> g; - // Avoid VC++ warning - (void)g; - return g.get(L, index, tracking); - } - }; - - template - struct getter::value>> { - typedef typename unique_usertype_traits::type P; - typedef typename unique_usertype_traits::actual_type Real; - - static Real& get(lua_State* L, int index, record& tracking) { - tracking.use(1); - P** pref = static_cast(lua_touserdata(L, index)); - detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); - Real* mem = static_cast(static_cast(fx + 1)); - return *mem; - } - }; - - template - struct getter> { - typedef std::tuple(nullptr, 0))...> R; - - template - static R apply(std::index_sequence<>, lua_State*, int, record&, TArgs&&... args) { - // Fuck you too, VC++ - return R{std::forward(args)...}; - } - - template - static R apply(std::index_sequence, lua_State* L, int index, record& tracking, TArgs&&... args) { - // Fuck you too, VC++ - typedef std::tuple_element_t> T; - return apply(std::index_sequence(), L, index, tracking, std::forward(args)..., stack::get(L, index + tracking.used, tracking)); - } - - static R get(lua_State* L, int index, record& tracking) { - return apply(std::make_index_sequence(), L, index, tracking); - } - }; - - template - struct getter> { - static decltype(auto) get(lua_State* L, int index, record& tracking) { - return std::pair(L, index)), decltype(stack::get(L, index))>{stack::get(L, index, tracking), stack::get(L, index + tracking.used, tracking)}; - } - }; - } // stack -} // sol - -// end of sol/stack_get.hpp - -// beginning of sol/stack_check_get.hpp - -namespace sol { - namespace stack { - template - struct check_getter { - typedef decltype(stack_detail::unchecked_get(nullptr, 0, std::declval())) R; - - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - if (!check(L, index, std::forward(handler))) { - tracking.use(static_cast(!lua_isnone(L, index))); - return nullopt; - } - return stack_detail::unchecked_get(L, index, tracking); - } - }; - - template - struct check_getter> { - template - static decltype(auto) get(lua_State* L, int index, Handler&&, record& tracking) { - return check_get(L, index, no_panic, tracking); - } - }; - - template - struct check_getter::value && lua_type_of::value == type::number>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - int isnum = 0; - lua_Integer value = lua_tointegerx(L, index, &isnum); - if (isnum == 0) { - type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t); - return nullopt; - } - tracking.use(1); - return static_cast(value); - } - }; - - template - struct check_getter::value && !meta::any_same::value>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - int isnum = 0; - lua_Integer value = lua_tointegerx(L, index, &isnum); - if (isnum == 0) { - type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t); - return nullopt; - } - tracking.use(1); - return static_cast(value); - } - }; - - template - struct check_getter::value>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - int isnum = 0; - lua_Number value = lua_tonumberx(L, index, &isnum); - if (isnum == 0) { - type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t); - return nullopt; - } - tracking.use(1); - return static_cast(value); - } - }; - - template - struct getter> { - static decltype(auto) get(lua_State* L, int index, record& tracking) { - return check_get(L, index, no_panic, tracking); - } - }; - } // stack -} // sol - -// end of sol/stack_check_get.hpp - -// beginning of sol/stack_push.hpp - -// beginning of sol/raii.hpp - -namespace sol { - namespace detail { - struct default_construct { - template - static void construct(T&& obj, Args&&... args) { - std::allocator> alloc{}; - alloc.construct(obj, std::forward(args)...); - } - - template - void operator()(T&& obj, Args&&... args) const { - construct(std::forward(obj), std::forward(args)...); - } - }; - - struct default_destruct { - template - static void destroy(T&& obj) { - std::allocator> alloc{}; - alloc.destroy(obj); - } - - template - void operator()(T&& obj) const { - destroy(std::forward(obj)); - } - }; - - struct deleter { - template - void operator()(T* p) const { - delete p; - } - }; - - template - inline std::unique_ptr make_unique_deleter(Args&&... args) { - return std::unique_ptr(new T(std::forward(args)...)); - } - - template - struct tagged { - T value; - template , tagged>> = meta::enabler> - tagged(Arg&& arg, Args&&... args) : value(std::forward(arg), std::forward(args)...) {} - }; - } // detail - - template - struct constructor_list {}; - - template - using constructors = constructor_list; - - const auto default_constructor = constructors>{}; - - struct no_construction {}; - const auto no_constructor = no_construction{}; - - struct call_construction {}; - const auto call_constructor = call_construction{}; - - template - struct constructor_wrapper { - std::tuple functions; - template , constructor_wrapper>> = meta::enabler> - constructor_wrapper(Arg&& arg, Args&&... args) : functions(std::forward(arg), std::forward(args)...) {} - }; - - template - inline auto initializers(Functions&&... functions) { - return constructor_wrapper...>(std::forward(functions)...); - } - - template - struct factory_wrapper { - std::tuple functions; - template , factory_wrapper>> = meta::enabler> - factory_wrapper(Arg&& arg, Args&&... args) : functions(std::forward(arg), std::forward(args)...) {} - }; - - template - inline auto factories(Functions&&... functions) { - return factory_wrapper...>(std::forward(functions)...); - } - - template - struct destructor_wrapper { - Function fx; - destructor_wrapper(Function f) : fx(std::move(f)) {} - }; - - template <> - struct destructor_wrapper {}; - - const destructor_wrapper default_destructor{}; - - template - inline auto destructor(Fx&& fx) { - return destructor_wrapper>(std::forward(fx)); - } - -} // sol - -// end of sol/raii.hpp - -#ifdef SOL_CODECVT_SUPPORT -#endif - -namespace sol { - namespace stack { - inline int push_environment_of(lua_State* L, int index = -1) { -#if SOL_LUA_VERSION < 502 - // Use lua_setfenv - lua_getfenv(L, index); - return 1; -#else - // Use upvalues as explained in Lua 5.2 and beyond's manual - if (lua_getupvalue(L, index, 1) == nullptr) { - push(L, lua_nil); - return 1; - } -#endif - return 1; - } - - template - int push_environment_of(const T& target) { - target.push(); - return push_environment_of(target.lua_state(), -1) + 1; - } - - template - struct pusher> { - template - static int push_fx(lua_State* L, F&& f, Args&&... args) { - // Basically, we store all user-data like this: - // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new - // data in the first sizeof(T*) bytes, and then however many bytes it takes to - // do the actual object. Things that are std::ref or plain T* are stored as - // just the sizeof(T*), and nothing else. - T** pointerpointer = static_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); - T*& referencereference = *pointerpointer; - T* allocationtarget = reinterpret_cast(pointerpointer + 1); - referencereference = allocationtarget; - std::allocator alloc{}; - alloc.construct(allocationtarget, std::forward(args)...); - f(); - return 1; - } - - template - static int push_keyed(lua_State* L, K&& k, Args&&... args) { - return push_fx(L, [&L, &k]() { - luaL_newmetatable(L, &k[0]); - lua_setmetatable(L, -2); - }, std::forward(args)...); - } - - template - static int push(lua_State* L, Args&&... args) { - return push_keyed(L, usertype_traits::metatable(), std::forward(args)...); - } - }; - - template - struct pusher> { - template - static int push_fx(lua_State* L, F&& f, T* obj) { - if (obj == nullptr) - return stack::push(L, lua_nil); - T** pref = static_cast(lua_newuserdata(L, sizeof(T*))); - *pref = obj; - f(); - return 1; - } - - template - static int push_keyed(lua_State* L, K&& k, T* obj) { - return push_fx(L, [&L, &k]() { - luaL_newmetatable(L, &k[0]); - lua_setmetatable(L, -2); - }, obj); - } - - static int push(lua_State* L, T* obj) { - return push_keyed(L, usertype_traits*>::metatable(), obj); - } - }; - - template <> - struct pusher { - template - static int push(lua_State* L, T&& obj) { - return stack::push(L, detail::ptr(obj)); - } - }; - - template - struct pusher { - template - static int push(lua_State* L, Args&&... args) { - return pusher>{}.push(L, std::forward(args)...); - } - }; - - template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { - template - static int push(lua_State* L, Args&&... args) { - return pusher>{}.push(L, std::forward(args)...); - } - }; - - template - struct pusher::value>> { - typedef typename unique_usertype_traits::type P; - typedef typename unique_usertype_traits::actual_type Real; - - template >> = meta::enabler> - static int push(lua_State* L, Arg&& arg) { - if (unique_usertype_traits::is_null(arg)) - return stack::push(L, lua_nil); - return push_deep(L, std::forward(arg)); - } - - template - static int push(lua_State* L, Arg0&& arg0, Arg0&& arg1, Args&&... args) { - return push_deep(L, std::forward(arg0), std::forward(arg1), std::forward(args)...); - } - - template - static int push_deep(lua_State* L, Args&&... args) { - P** pref = static_cast(lua_newuserdata(L, sizeof(P*) + sizeof(detail::special_destruct_func) + sizeof(Real))); - detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); - Real* mem = static_cast(static_cast(fx + 1)); - *fx = detail::special_destruct; - detail::default_construct::construct(mem, std::forward(args)...); - *pref = unique_usertype_traits::get(*mem); - if (luaL_newmetatable(L, &usertype_traits>::metatable()[0]) == 1) { - set_field(L, "__gc", detail::unique_destruct

); - } - lua_setmetatable(L, -2); - return 1; - } - }; - - template - struct pusher> { - static int push(lua_State* L, const std::reference_wrapper& t) { - return stack::push(L, std::addressof(detail::deref(t.get()))); - } - }; - - template - struct pusher::value>> { - static int push(lua_State* L, const T& value) { - lua_pushnumber(L, value); - return 1; - } - }; - - template - struct pusher, std::is_signed>::value>> { - static int push(lua_State* L, const T& value) { - lua_pushinteger(L, static_cast(value)); - return 1; - } - }; - - template - struct pusher::value>> { - static int push(lua_State* L, const T& value) { - if (std::is_same::value) { - return stack::push(L, static_cast(value)); - } - return stack::push(L, static_cast>(value)); - } - }; - - template - struct pusher, std::is_unsigned>::value>> { - static int push(lua_State* L, const T& value) { - lua_pushinteger(L, static_cast(value)); - return 1; - } - }; - - template - struct pusher, std::enable_if_t>>::value>> { - static int push(lua_State* L, const as_table_t& tablecont) { - auto& cont = detail::deref(detail::unwrap(tablecont.source)); - lua_createtable(L, static_cast(cont.size()), 0); - int tableindex = lua_gettop(L); - std::size_t index = 1; - for (const auto& i : cont) { -#if SOL_LUA_VERSION >= 503 - int p = stack::push(L, i); - for (int pi = 0; pi < p; ++pi) { - lua_seti(L, tableindex, static_cast(index++)); - } -#else - lua_pushinteger(L, static_cast(index)); - int p = stack::push(L, i); - if (p == 1) { - ++index; - lua_settable(L, tableindex); - } - else { - int firstindex = tableindex + 1 + 1; - for (int pi = 0; pi < p; ++pi) { - stack::push(L, index); - lua_pushvalue(L, firstindex); - lua_settable(L, tableindex); - ++index; - ++firstindex; - } - lua_pop(L, 1 + p); - } -#endif - } - // TODO: figure out a better way to do this...? - //set_field(L, -1, cont.size()); - return 1; - } - }; - - template - struct pusher, std::enable_if_t>>::value>> { - static int push(lua_State* L, const as_table_t& tablecont) { - auto& cont = detail::deref(detail::unwrap(tablecont.source)); - lua_createtable(L, static_cast(cont.size()), 0); - int tableindex = lua_gettop(L); - for (const auto& pair : cont) { - set_field(L, pair.first, pair.second, tableindex); - } - return 1; - } - }; - - template - struct pusher::value || std::is_base_of::value>> { - static int push(lua_State* L, const T& ref) { - return ref.push(L); - } - - static int push(lua_State* L, T&& ref) { - return ref.push(L); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, bool b) { - lua_pushboolean(L, b); - return 1; - } - }; - - template<> - struct pusher { - static int push(lua_State* L, lua_nil_t) { - lua_pushnil(L); - return 1; - } - }; - - template<> - struct pusher { - static int push(lua_State* L, metatable_t) { - lua_pushlstring(L, "__mt", 4); - return 1; - } - }; - - template<> - struct pusher> { - static int push(lua_State* L, lua_CFunction func, int n = 0) { - lua_pushcclosure(L, func, n); - return 1; - } - }; - - template<> - struct pusher { - static int push(lua_State* L, lua_CFunction func, int n = 0) { - lua_pushcclosure(L, func, n); - return 1; - } - }; - - template<> - struct pusher { - static int push(lua_State* L, c_closure cc) { - lua_pushcclosure(L, cc.c_function, cc.upvalues); - return 1; - } - }; - - template - struct pusher> { - template - static int push(std::index_sequence, lua_State* L, T&& c) { - int pushcount = multi_push(L, detail::forward_get(c.upvalues)...); - return stack::push(L, c_closure(c.c_function, pushcount)); - } - - template - static int push(lua_State* L, T&& c) { - return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward(c)); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, void* userdata) { - lua_pushlightuserdata(L, userdata); - return 1; - } - }; - - template<> - struct pusher { - static int push(lua_State* L, lightuserdata_value userdata) { - lua_pushlightuserdata(L, userdata); - return 1; - } - }; - - template - struct pusher> { - static int push(lua_State* L, light l) { - lua_pushlightuserdata(L, static_cast(l.value)); - return 1; - } - }; - - template - struct pusher> { - template - static int push_with(lua_State* L, Key&& name, Args&&... args) { - // A dumb pusher - void* rawdata = lua_newuserdata(L, sizeof(T)); - T* data = static_cast(rawdata); - std::allocator alloc; - alloc.construct(data, std::forward(args)...); - if (with_meta) { - lua_CFunction cdel = detail::user_alloc_destroy; - // Make sure we have a plain GC set for this data - if (luaL_newmetatable(L, name) != 0) { - lua_pushcclosure(L, cdel, 0); - lua_setfield(L, -2, "__gc"); - } - lua_setmetatable(L, -2); - } - return 1; - } - - template , no_metatable_t, metatable_t>> = meta::enabler> - static int push(lua_State* L, Arg&& arg, Args&&... args) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(arg), std::forward(args)...); - } - - template - static int push(lua_State* L, no_metatable_t, Args&&... args) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(args)...); - } - - template - static int push(lua_State* L, metatable_t, Key&& key, Args&&... args) { - const auto name = &key[0]; - return push_with(L, name, std::forward(args)...); - } - - static int push(lua_State* L, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, u.value); - } - - static int push(lua_State* L, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::move(u.value)); - } - - static int push(lua_State* L, no_metatable_t, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, u.value); - } - - static int push(lua_State* L, no_metatable_t, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::move(u.value)); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, userdata_value data) { - void** ud = static_cast(lua_newuserdata(L, sizeof(void*))); - *ud = data.value; - return 1; - } - }; - - template<> - struct pusher { - static int push_sized(lua_State* L, const char* str, std::size_t len) { - lua_pushlstring(L, str, len); - return 1; - } - - static int push(lua_State* L, const char* str) { - if (str == nullptr) - return stack::push(L, lua_nil); - return push_sized(L, str, std::char_traits::length(str)); - } - - static int push(lua_State* L, const char* strb, const char* stre) { - return push_sized(L, strb, stre - strb); - } - - static int push(lua_State* L, const char* str, std::size_t len) { - return push_sized(L, str, len); - } - }; - - template - struct pusher { - static int push(lua_State* L, const char(&str)[N]) { - lua_pushlstring(L, str, N - 1); - return 1; - } - - static int push(lua_State* L, const char(&str)[N], std::size_t sz) { - lua_pushlstring(L, str, sz); - return 1; - } - }; - - template <> - struct pusher { - static int push(lua_State* L, char c) { - const char str[2] = { c, '\0' }; - return stack::push(L, str, 1); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, const std::string& str) { - lua_pushlstring(L, str.c_str(), str.size()); - return 1; - } - - static int push(lua_State* L, const std::string& str, std::size_t sz) { - lua_pushlstring(L, str.c_str(), sz); - return 1; - } - }; - - template<> - struct pusher { - static int push(lua_State* L, meta_function m) { - const std::string& str = to_string(m); - lua_pushlstring(L, str.c_str(), str.size()); - return 1; - } - }; - -#ifdef SOL_CODECVT_SUPPORT - template<> - struct pusher { - static int push(lua_State* L, const wchar_t* wstr) { - return push(L, wstr, std::char_traits::length(wstr)); - } - - static int push(lua_State* L, const wchar_t* wstr, std::size_t sz) { - return push(L, wstr, wstr + sz); - } - - static int push(lua_State* L, const wchar_t* strb, const wchar_t* stre) { - if (sizeof(wchar_t) == 2) { - static std::wstring_convert> convert; - std::string u8str = convert.to_bytes(strb, stre); - return stack::push(L, u8str); - } - static std::wstring_convert> convert; - std::string u8str = convert.to_bytes(strb, stre); - return stack::push(L, u8str); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, const char16_t* u16str) { - return push(L, u16str, std::char_traits::length(u16str)); - } - - static int push(lua_State* L, const char16_t* u16str, std::size_t sz) { - return push(L, u16str, u16str + sz); - } - - static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { -#ifdef _MSC_VER - static std::wstring_convert, int16_t> convert; - std::string u8str = convert.to_bytes(reinterpret_cast(strb), reinterpret_cast(stre)); -#else - static std::wstring_convert, char16_t> convert; - std::string u8str = convert.to_bytes(strb, stre); -#endif // VC++ is a shit - return stack::push(L, u8str); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, const char32_t* u32str) { - return push(L, u32str, u32str + std::char_traits::length(u32str)); - } - - static int push(lua_State* L, const char32_t* u32str, std::size_t sz) { - return push(L, u32str, u32str + sz); - } - - static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { -#ifdef _MSC_VER - static std::wstring_convert, int32_t> convert; - std::string u8str = convert.to_bytes(reinterpret_cast(strb), reinterpret_cast(stre)); -#else - static std::wstring_convert, char32_t> convert; - std::string u8str = convert.to_bytes(strb, stre); -#endif // VC++ is a shit - return stack::push(L, u8str); - } - }; - - template - struct pusher { - static int push(lua_State* L, const wchar_t(&str)[N]) { - return push(L, str, N - 1); - } - - static int push(lua_State* L, const wchar_t(&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template - struct pusher { - static int push(lua_State* L, const char16_t(&str)[N]) { - return push(L, str, N - 1); - } - - static int push(lua_State* L, const char16_t(&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template - struct pusher { - static int push(lua_State* L, const char32_t(&str)[N]) { - return push(L, str, N - 1); - } - - static int push(lua_State* L, const char32_t(&str)[N], std::size_t sz) { - return stack::push(L, str, str + sz); - } - }; - - template <> - struct pusher { - static int push(lua_State* L, wchar_t c) { - const wchar_t str[2] = { c, '\0' }; - return stack::push(L, str, 1); - } - }; - - template <> - struct pusher { - static int push(lua_State* L, char16_t c) { - const char16_t str[2] = { c, '\0' }; - return stack::push(L, str, 1); - } - }; - - template <> - struct pusher { - static int push(lua_State* L, char32_t c) { - const char32_t str[2] = { c, '\0' }; - return stack::push(L, str, 1); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, const std::wstring& wstr) { - return push(L, wstr.data(), wstr.size()); - } - - static int push(lua_State* L, const std::wstring& wstr, std::size_t sz) { - return stack::push(L, wstr.data(), wstr.data() + sz); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, const std::u16string& u16str) { - return push(L, u16str, u16str.size()); - } - - static int push(lua_State* L, const std::u16string& u16str, std::size_t sz) { - return stack::push(L, u16str.data(), u16str.data() + sz); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, const std::u32string& u32str) { - return push(L, u32str, u32str.size()); - } - - static int push(lua_State* L, const std::u32string& u32str, std::size_t sz) { - return stack::push(L, u32str.data(), u32str.data() + sz); - } - }; -#endif // codecvt Header Support - - template - struct pusher> { - template - static int push(std::index_sequence, lua_State* L, T&& t) { - int pushcount = 0; - (void)detail::swallow{ 0, (pushcount += stack::push(L, - detail::forward_get(t) - ), 0)... }; - return pushcount; - } - - template - static int push(lua_State* L, T&& t) { - return push(std::index_sequence_for(), L, std::forward(t)); - } - }; - - template - struct pusher> { - template - static int push(lua_State* L, T&& t) { - int pushcount = stack::push(L, detail::forward_get<0>(t)); - pushcount += stack::push(L, detail::forward_get<1>(t)); - return pushcount; - } - }; - - template - struct pusher> { - template - static int push(lua_State* L, T&& t) { - if (t == nullopt) { - return stack::push(L, nullopt); - } - return stack::push(L, t.value()); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, nullopt_t) { - return stack::push(L, lua_nil); - } - }; - - template<> - struct pusher { - static int push(lua_State* L, std::nullptr_t) { - return stack::push(L, lua_nil); - } - }; - - template<> - struct pusher { - static int push(lua_State*, const this_state&) { - return 0; - } - }; - - template<> - struct pusher { - static int push(lua_State* L, const new_table& nt) { - lua_createtable(L, nt.sequence_hint, nt.map_hint); - return 1; - } - }; - } // stack -} // sol - -// end of sol/stack_push.hpp - -// beginning of sol/stack_pop.hpp - -namespace sol { - namespace stack { - template - struct popper { - inline static decltype(auto) pop(lua_State* L) { - record tracking{}; - decltype(auto) r = get(L, -lua_size::value, tracking); - lua_pop(L, tracking.used); - return r; - } - }; - - template - struct popper>::value>> { - static_assert(meta::neg>>::value, "You cannot pop something that derives from stack_reference: it will not remain on the stack and thusly will go out of scope!"); - }; - } // stack -} // sol - -// end of sol/stack_pop.hpp - -// beginning of sol/stack_field.hpp - -namespace sol { - namespace stack { - template - struct field_getter { - template - void get(lua_State* L, Key&& key, int tableindex = -2) { - push(L, std::forward(key)); - lua_gettable(L, tableindex); - } - }; - - template - struct field_getter { - template - void get(lua_State* L, Key&& key, int tableindex = -2) { - push(L, std::forward(key)); - lua_rawget(L, tableindex); - } - }; - - template - struct field_getter { - void get(lua_State* L, metatable_t, int tableindex = -1) { - if (lua_getmetatable(L, tableindex) == 0) - push(L, lua_nil); - } - }; - - template - struct field_getter { - void get(lua_State* L, env_t, int tableindex = -1) { -#if SOL_LUA_VERSION < 502 - // Use lua_setfenv - lua_getfenv(L, tableindex); -#else - // Use upvalues as explained in Lua 5.2 and beyond's manual - if (lua_getupvalue(L, tableindex, 1) == nullptr) { - push(L, lua_nil); - } -#endif - } - }; - - template - struct field_getter::value>> { - template - void get(lua_State* L, Key&& key, int = -1) { - lua_getglobal(L, &key[0]); - } - }; - - template - struct field_getter::value>> { - template - void get(lua_State* L, Key&& key, int tableindex = -1) { - lua_getfield(L, tableindex, &key[0]); - } - }; - -#if SOL_LUA_VERSION >= 503 - template - struct field_getter::value>> { - template - void get(lua_State* L, Key&& key, int tableindex = -1) { - lua_geti(L, tableindex, static_cast(key)); - } - }; -#endif // Lua 5.3.x - -#if SOL_LUA_VERSION >= 502 - template - struct field_getter { - void get(lua_State* L, void* key, int tableindex = -1) { - lua_rawgetp(L, tableindex, key); - } - }; -#endif // Lua 5.3.x - - template - struct field_getter::value>> { - template - void get(lua_State* L, Key&& key, int tableindex = -1) { - lua_rawgeti(L, tableindex, static_cast(key)); - } - }; - - template - struct field_getter, b, raw, C> { - template - void apply(std::index_sequence<0, I...>, lua_State* L, Keys&& keys, int tableindex) { - get_field(L, detail::forward_get<0>(keys), tableindex); - void(detail::swallow{ (get_field(L, detail::forward_get(keys)), 0)... }); - reference saved(L, -1); - lua_pop(L, static_cast(sizeof...(I))); - saved.push(); - } - - template - void get(lua_State* L, Keys&& keys) { - apply(std::make_index_sequence(), L, std::forward(keys), lua_absindex(L, -1)); - } - - template - void get(lua_State* L, Keys&& keys, int tableindex) { - apply(std::make_index_sequence(), L, std::forward(keys), tableindex); - } - }; - - template - struct field_getter, b, raw, C> { - template - void get(lua_State* L, Keys&& keys, int tableindex) { - get_field(L, detail::forward_get<0>(keys), tableindex); - get_field(L, detail::forward_get<1>(keys)); - reference saved(L, -1); - lua_pop(L, static_cast(2)); - saved.push(); - } - - template - void get(lua_State* L, Keys&& keys) { - get_field(L, detail::forward_get<0>(keys)); - get_field(L, detail::forward_get<1>(keys)); - reference saved(L, -1); - lua_pop(L, static_cast(2)); - saved.push(); - } - }; - - template - struct field_setter { - template - void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) { - push(L, std::forward(key)); - push(L, std::forward(value)); - lua_settable(L, tableindex); - } - }; - - template - struct field_setter { - template - void set(lua_State* L, Key&& key, Value&& value, int tableindex = -3) { - push(L, std::forward(key)); - push(L, std::forward(value)); - lua_rawset(L, tableindex); - } - }; - - template - struct field_setter { - template - void set(lua_State* L, metatable_t, Value&& value, int tableindex = -2) { - push(L, std::forward(value)); - lua_setmetatable(L, tableindex); - } - }; - - template - struct field_setter::value>> { - template - void set(lua_State* L, Key&& key, Value&& value, int = -2) { - push(L, std::forward(value)); - lua_setglobal(L, &key[0]); - } - }; - - template - struct field_setter::value>> { - template - void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { - push(L, std::forward(value)); - lua_setfield(L, tableindex, &key[0]); - } - }; - -#if SOL_LUA_VERSION >= 503 - template - struct field_setter::value>> { - template - void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { - push(L, std::forward(value)); - lua_seti(L, tableindex, static_cast(key)); - } - }; -#endif // Lua 5.3.x - - template - struct field_setter::value>> { - template - void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { - push(L, std::forward(value)); - lua_rawseti(L, tableindex, static_cast(key)); - } - }; - -#if SOL_LUA_VERSION >= 502 - template - struct field_setter { - template - void set(lua_State* L, void* key, Value&& value, int tableindex = -2) { - push(L, std::forward(value)); - lua_rawsetp(L, tableindex, key); - } - }; -#endif // Lua 5.2.x - - template - struct field_setter, b, raw, C> { - template - void apply(std::index_sequence, lua_State* L, Key&& keys, Value&& value, int tableindex) { - I < 1 ? - set_field(L, detail::forward_get(keys), std::forward(value), tableindex) : - set_field(L, detail::forward_get(keys), std::forward(value)); - } - - template - void apply(std::index_sequence, lua_State* L, Keys&& keys, Value&& value, int tableindex) { - I0 < 1 ? get_field(L, detail::forward_get(keys), tableindex) : get_field(L, detail::forward_get(keys), -1); - apply(std::index_sequence(), L, std::forward(keys), std::forward(value), -1); - } - - template - void top_apply(std::index_sequence, lua_State* L, Keys&& keys, Value&& value, int tableindex) { - apply(std::index_sequence(), L, std::forward(keys), std::forward(value), tableindex); - lua_pop(L, static_cast(sizeof...(I))); - } - - template - void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -3) { - top_apply(std::make_index_sequence(), L, std::forward(keys), std::forward(value), tableindex); - } - }; - - template - struct field_setter, b, raw, C> { - template - void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) { - get_field(L, detail::forward_get<0>(keys), tableindex); - set_field(L, detail::forward_get<1>(keys), std::forward(value)); - lua_pop(L, 1); - } - }; - } // stack -} // sol - -// end of sol/stack_field.hpp - -// beginning of sol/stack_probe.hpp - -namespace sol { - namespace stack { - template - struct probe_field_getter { - template - probe get(lua_State* L, Key&& key, int tableindex = -2) { - if (!b && !maybe_indexable(L, tableindex)) { - return probe(false, 0); - } - get_field(L, std::forward(key), tableindex); - return probe(!check(L), 1); - } - }; - - template - struct probe_field_getter, b, raw, C> { - template - probe get(lua_State* L, Keys&& keys, int tableindex = -2) { - if (!b && !maybe_indexable(L, tableindex)) { - return probe(false, 0); - } - get_field(L, std::get<0>(keys), tableindex); - if (!maybe_indexable(L)) { - return probe(false, 1); - } - get_field(L, std::get<1>(keys), tableindex); - return probe(!check(L), 2); - } - }; - - template - struct probe_field_getter, b, raw, C> { - template - probe apply(std::index_sequence, int sofar, lua_State* L, Keys&& keys, int tableindex) { - get_field < I < 1 && b, raw>(L, std::get(keys), tableindex); - return probe(!check(L), sofar); - } - - template - probe apply(std::index_sequence, int sofar, lua_State* L, Keys&& keys, int tableindex) { - get_field < I < 1 && b, raw>(L, std::get(keys), tableindex); - if (!maybe_indexable(L)) { - return probe(false, sofar); - } - return apply(std::index_sequence(), sofar + 1, L, std::forward(keys), -1); - } - - template - probe get(lua_State* L, Keys&& keys, int tableindex = -2) { - if (!b && !maybe_indexable(L, tableindex)) { - return probe(false, 0); - } - return apply(std::index_sequence_for(), 1, L, std::forward(keys), tableindex); - } - }; - } // stack -} // sol - -// end of sol/stack_probe.hpp - -#include - -namespace sol { - namespace stack { - namespace stack_detail { - template - inline int push_as_upvalues(lua_State* L, T& item) { - typedef std::decay_t TValue; - const static std::size_t itemsize = sizeof(TValue); - const static std::size_t voidsize = sizeof(void*); - const static std::size_t voidsizem1 = voidsize - 1; - const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; - typedef std::array data_t; - - data_t data{ {} }; - std::memcpy(&data[0], std::addressof(item), itemsize); - int pushcount = 0; - for (auto&& v : data) { - pushcount += push(L, lightuserdata_value(v)); - } - return pushcount; - } - - template - inline std::pair get_as_upvalues(lua_State* L, int index = 1) { - const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); - typedef std::array data_t; - data_t voiddata{ {} }; - for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { - voiddata[i] = get(L, upvalue_index(index++)); - } - return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); - } - - struct evaluator { - template - static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) { - return std::forward(fx)(std::forward(args)...); - } - - template - static decltype(auto) eval(types, std::index_sequence, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) { - return eval(types(), std::index_sequence(), L, start, tracking, std::forward(fx), std::forward(fxargs)..., stack_detail::unchecked_get(L, start + tracking.used, tracking)); - } - }; - - template ::value>> - inline decltype(auto) call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { -#ifndef _MSC_VER - static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); -#endif // This compiler make me so fucking sad - multi_check(L, start, type_panic); - record tracking{}; - return evaluator{}.eval(ta, tai, L, start, tracking, std::forward(fx), std::forward(args)...); - } - - template - inline void call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { -#ifndef _MSC_VER - static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); -#endif // This compiler make me so fucking sad - multi_check(L, start, type_panic); - record tracking{}; - evaluator{}.eval(ta, tai, L, start, tracking, std::forward(fx), std::forward(args)...); - } - } // stack_detail - - template - int set_ref(lua_State* L, T&& arg, int tableindex = -2) { - push(L, std::forward(arg)); - return luaL_ref(L, tableindex); - } - - template ::value>> - inline decltype(auto) call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { - typedef std::make_index_sequence args_indices; - return stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); - } - - template ::value>> - inline decltype(auto) call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - return call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); - } - - template - inline void call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { - typedef std::make_index_sequence args_indices; - stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); - } - - template - inline void call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); - } - - template ::value>> - inline decltype(auto) call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - return call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); - } - - template - inline void call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); - } - - template - inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { - call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); - lua_settop(L, 0); - return 0; - } - - template>::value>> - inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { - decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); - lua_settop(L, 0); - return push_reference(L, std::forward(r)); - } - - template - inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { - typedef lua_bind_traits> traits_type; - typedef typename traits_type::args_list args_list; - typedef typename traits_type::returns_list returns_list; - return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); - } - - inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { - if (lua_gettop(L) == 0) { - return call_syntax::dot; - } - luaL_getmetatable(L, key.c_str()); - auto pn = pop_n(L, 1); - if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { - return call_syntax::dot; - } - return call_syntax::colon; - } - - inline void script(lua_State* L, const std::string& code) { - if (luaL_dostring(L, code.c_str())) { - lua_error(L); - } - } - - inline void script_file(lua_State* L, const std::string& filename) { - if (luaL_dofile(L, filename.c_str())) { - lua_error(L); - } - } - - inline void luajit_exception_handler(lua_State* L, int(*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) { -#ifdef SOL_LUAJIT - lua_pushlightuserdata(L, (void*)handler); - auto pn = pop_n(L, 1); - luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); -#else - (void)L; - (void)handler; -#endif - } - - inline void luajit_exception_off(lua_State* L) { -#ifdef SOL_LUAJIT - luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF); -#else - (void)L; -#endif - } - } // stack -} // sol - -// end of sol/stack.hpp - -// beginning of sol/object_base.hpp - -namespace sol { - - template - class basic_object_base : public base_t { - private: - template - decltype(auto) as_stack(std::true_type) const { - return stack::get(base_t::lua_state(), base_t::stack_index()); - } - - template - decltype(auto) as_stack(std::false_type) const { - base_t::push(); - return stack::pop(base_t::lua_state()); - } - - template - bool is_stack(std::true_type) const { - return stack::check(base_t::lua_state(), base_t::stack_index(), no_panic); - } - - template - bool is_stack(std::false_type) const { - int r = base_t::registry_index(); - if (r == LUA_REFNIL) - return meta::any_same, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false; - if (r == LUA_NOREF) - return false; - auto pp = stack::push_pop(*this); - return stack::check(base_t::lua_state(), -1, no_panic); - } - - public: - basic_object_base() noexcept = default; - basic_object_base(const basic_object_base&) = default; - basic_object_base(basic_object_base&&) = default; - basic_object_base& operator=(const basic_object_base&) = default; - basic_object_base& operator=(basic_object_base&&) = default; - template , basic_object_base>>> = meta::enabler> - basic_object_base(T&& arg, Args&&... args) : base_t(std::forward(arg), std::forward(args)...) { } - - template - decltype(auto) as() const { - return as_stack(std::is_same()); - } - - template - bool is() const { - return is_stack(std::is_same()); - } - }; -} // sol - -// end of sol/object_base.hpp - -// beginning of sol/userdata.hpp - -namespace sol { - template - class basic_userdata : public basic_table { - typedef basic_table base_t; - public: - basic_userdata() noexcept = default; - template , basic_userdata>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_userdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_userdata>::value) { - auto pp = stack::push_pop(*this); - type_assert(base_t::lua_state(), -1, type::userdata); - } -#endif // Safety - } - basic_userdata(const basic_userdata&) = default; - basic_userdata(basic_userdata&&) = default; - basic_userdata& operator=(const basic_userdata&) = default; - basic_userdata& operator=(basic_userdata&&) = default; - basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {} - basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> - basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} - basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(L, index, type_panic); -#endif // Safety - } - basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - stack::check(L, index, type_panic); -#endif // Safety - } - }; - - template - class basic_lightuserdata : public basic_object_base { - typedef basic_object_base base_t; - public: - basic_lightuserdata() noexcept = default; - template , basic_lightuserdata>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_lightuserdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_lightuserdata>::value) { - auto pp = stack::push_pop(*this); - type_assert(base_t::lua_state(), -1, type::lightuserdata); - } -#endif // Safety - } - basic_lightuserdata(const basic_lightuserdata&) = default; - basic_lightuserdata(basic_lightuserdata&&) = default; - basic_lightuserdata& operator=(const basic_lightuserdata&) = default; - basic_lightuserdata& operator=(basic_lightuserdata&&) = default; - basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} - basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> - basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} - basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(L, index, type_panic); -#endif // Safety - } - basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - stack::check(L, index, type_panic); -#endif // Safety - } - }; - -} // sol - -// end of sol/userdata.hpp - -// beginning of sol/as_args.hpp - -namespace sol { - template - struct to_args_t { - T src; - }; - - template - auto as_args(Source&& source) { - return to_args_t{ std::forward(source) }; - } - - namespace stack { - template - struct pusher> { - int push(lua_State* L, const to_args_t& e) { - int p = 0; - for (const auto& i : e.src) { - p += stack::push(L, i); - } - return p; - } - }; - } -} // sol - -// end of sol/as_args.hpp - -// beginning of sol/variadic_args.hpp - -// beginning of sol/stack_proxy.hpp - -// beginning of sol/function.hpp - -// beginning of sol/function_result.hpp - -// beginning of sol/proxy_base.hpp - -namespace sol { - struct proxy_base_tag {}; - - template - struct proxy_base : proxy_base_tag { - operator std::string() const { - const Super& super = *static_cast(static_cast(this)); - return super.template get(); - } - - template>, is_proxy_primitive>> = meta::enabler> - operator T () const { - const Super& super = *static_cast(static_cast(this)); - return super.template get(); - } - - template>, meta::neg>>> = meta::enabler> - operator T& () const { - const Super& super = *static_cast(static_cast(this)); - return super.template get(); - } - }; -} // sol - -// end of sol/proxy_base.hpp - -#include - -namespace sol { - struct function_result : public proxy_base { - private: - lua_State* L; - int index; - int returncount; - - public: - function_result() = default; - function_result(lua_State* Ls, int idx = -1, int retnum = 0) : L(Ls), index(idx), returncount(retnum) { - - } - function_result(const function_result&) = default; - function_result& operator=(const function_result&) = default; - function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - } - function_result& operator=(function_result&& o) { - L = o.L; - index = o.index; - returncount = o.returncount; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - return *this; - } - - template - decltype(auto) get() const { - return stack::get(L, index); - } - - call_status status() const noexcept { - return call_status::ok; - } - - bool valid() const noexcept { - return status() == call_status::ok || status() == call_status::yielded; - } - - lua_State* lua_state() const { return L; }; - int stack_index() const { return index; }; - - ~function_result() { - lua_pop(L, returncount); - } - }; -} // sol - -// end of sol/function_result.hpp - -// beginning of sol/function_types.hpp - -// beginning of sol/function_types_core.hpp - -// beginning of sol/wrapper.hpp - -namespace sol { - - template - struct wrapper { - typedef lua_bind_traits traits_type; - typedef typename traits_type::args_list args_list; - typedef typename traits_type::args_list free_args_list; - typedef typename traits_type::returns_list returns_list; - - template - static decltype(auto) call(F& f, Args&&... args) { - return f(std::forward(args)...); - } - - struct caller { - template - decltype(auto) operator()(F& fx, Args&&... args) const { - return call(fx, std::forward(args)...); - } - }; - }; - - template - struct wrapper>>::value>> { - typedef lua_bind_traits traits_type; - typedef typename traits_type::args_list args_list; - typedef typename traits_type::args_list free_args_list; - typedef typename traits_type::returns_list returns_list; - - template - static decltype(auto) invoke(Args&&... args) { - return fx(std::forward(args)...); - } - - template - static decltype(auto) call(F& fx, Args&&... args) { - return fx(std::forward(args)...); - } - - struct caller { - template - decltype(auto) operator()(F& fx, Args&&... args) const { - return call(fx, std::forward(args)...); - } - }; - - template - struct invoker { - template - decltype(auto) operator()(Args&&... args) const { - return invoke(std::forward(args)...); - } - }; - }; - - template - struct wrapper>::value>> { - typedef lua_bind_traits traits_type; - typedef typename traits_type::object_type object_type; - typedef typename traits_type::return_type return_type; - typedef typename traits_type::args_list args_list; - typedef types free_args_list; - typedef typename traits_type::returns_list returns_list; - - template - static decltype(auto) invoke(object_type& mem, Args&&... args) { - return (mem.*fx)(std::forward(args)...); - } - - template - static decltype(auto) call(Fx&& fx, object_type& mem) { - return (mem.*fx); - } - - template - static void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&...) { - (mem.*fx) = std::forward(arg); - } - - struct caller { - template - decltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const { - return call(std::forward(fx), mem, std::forward(args)...); - } - }; - - template - struct invoker { - template - decltype(auto) operator()(Args&&... args) const { - return invoke(std::forward(args)...); - } - }; - }; - - template - struct member_function_wrapper { - typedef O object_type; - typedef lua_bind_traits traits_type; - typedef typename traits_type::args_list args_list; - typedef types free_args_list; - typedef meta::tuple_types returns_list; - - template - static R invoke(O& mem, Args&&... args) { - return (mem.*fx)(std::forward(args)...); - } - - template - static R call(Fx&& fx, O& mem, Args&&... args) { - return (mem.*fx)(std::forward(args)...); - } - - struct caller { - template - decltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const { - return call(std::forward(fx), mem, std::forward(args)...); - } - }; - - template - struct invoker { - template - decltype(auto) operator()(O& mem, Args&&... args) const { - return invoke(mem, std::forward(args)...); - } - }; - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - - template - struct wrapper : public member_function_wrapper { - - }; - -} // sol - -// end of sol/wrapper.hpp - -namespace sol { - namespace function_detail { - template - inline int call(lua_State* L) { - Fx& fx = stack::get>(L, upvalue_index(1)); - return fx(L); - } - } // function_detail -} // sol - -// end of sol/function_types_core.hpp - -// beginning of sol/function_types_templated.hpp - -// beginning of sol/call.hpp - -// beginning of sol/protect.hpp - -namespace sol { - - template - struct protect_t { - T value; - - template >> = meta::enabler> - protect_t(Arg&& arg, Args&&... args) : value(std::forward(arg), std::forward(args)...) {} - - protect_t(const protect_t&) = default; - protect_t(protect_t&&) = default; - protect_t& operator=(const protect_t&) = default; - protect_t& operator=(protect_t&&) = default; - - }; - - template - auto protect(T&& value) { - return protect_t>(std::forward(value)); - } - -} // sol - -// end of sol/protect.hpp - -// beginning of sol/property.hpp - -namespace sol { - - struct no_prop { }; - - template - struct property_wrapper { - typedef std::integral_constant::value> can_read; - typedef std::integral_constant::value> can_write; - typedef std::conditional_t Read; - typedef std::conditional_t Write; - Read read; - Write write; - - template - property_wrapper(Rx&& r, Wx&& w) : read(std::forward(r)), write(std::forward(w)) {} - }; - - namespace property_detail { - template - inline decltype(auto) property(std::true_type, R&& read, W&& write) { - return property_wrapper, std::decay_t>(std::forward(read), std::forward(write)); - } - template - inline decltype(auto) property(std::false_type, W&& write, R&& read) { - return property_wrapper, std::decay_t>(std::forward(read), std::forward(write)); - } - template - inline decltype(auto) property(std::true_type, R&& read) { - return property_wrapper, void>(std::forward(read), no_prop()); - } - template - inline decltype(auto) property(std::false_type, W&& write) { - return property_wrapper>(no_prop(), std::forward(write)); - } - } // property_detail - - template - inline decltype(auto) property(F&& f, G&& g) { - typedef lua_bind_traits> left_traits; - typedef lua_bind_traits> right_traits; - return property_detail::property(meta::boolean<(left_traits::free_arity < right_traits::free_arity)>(), std::forward(f), std::forward(g)); - } - - template - inline decltype(auto) property(F&& f) { - typedef lua_bind_traits> left_traits; - return property_detail::property(meta::boolean<(left_traits::free_arity < 2)>(), std::forward(f)); - } - - template - inline decltype(auto) readonly_property(F&& f) { - return property_detail::property(std::true_type(), std::forward(f)); - } - - template - inline decltype(auto) writeonly_property(F&& f) { - return property_detail::property(std::false_type(), std::forward(f)); - } - - // Allow someone to make a member variable readonly (const) - template - inline auto readonly(R T::* v) { - typedef const R C; - return static_cast(v); - } - - template - struct var_wrapper { - T value; - template - var_wrapper(Args&&... args) : value(std::forward(args)...) {} - var_wrapper(const var_wrapper&) = default; - var_wrapper(var_wrapper&&) = default; - var_wrapper& operator=(const var_wrapper&) = default; - var_wrapper& operator=(var_wrapper&&) = default; - }; - - template - inline auto var(V&& v) { - typedef meta::unqualified_t T; - return var_wrapper(std::forward(v)); - } - -} // sol - -// end of sol/property.hpp - -namespace sol { - namespace function_detail { - inline int no_construction_error(lua_State* L) { - return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); - } - } - - namespace call_detail { - - template - inline auto& pick(std::true_type, property_wrapper& f) { - return f.read; - } - - template - inline auto& pick(std::false_type, property_wrapper& f) { - return f.write; - } - - template - struct void_call : void_call> {}; - - template - struct void_call> { - static void call(Args...) {} - }; - - template - struct constructor_match { - T* obj; - - constructor_match(T* o) : obj(o) {} - - template - int operator()(types, index_value, types r, types a, lua_State* L, int, int start) const { - detail::default_construct func{}; - return stack::call_into_lua(r, a, L, start, func, obj); - } - }; - - namespace overload_detail { - template - inline int overload_match_arity(types<>, std::index_sequence<>, std::index_sequence, Match&&, lua_State* L, int, int, Args&&...) { - return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types"); - } - - template - inline int overload_match_arity(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; - typedef meta::tuple_types return_types; - typedef typename traits::free_args_list args_list; - // compile-time eliminate any functions that we know ahead of time are of improper arity - if (meta::find_in_pack_v, index_value...>::value) { - return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) { - return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - stack::record tracking{}; - if (!stack::stack_detail::check_types{}.check(args_list(), L, start, no_panic, tracking)) { - return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); - } - - template - inline int overload_match_arity_single(types<>, std::index_sequence<>, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - - template - inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; - typedef meta::tuple_types return_types; - typedef typename traits::free_args_list args_list; - // compile-time eliminate any functions that we know ahead of time are of improper arity - if (meta::find_in_pack_v, index_value...>::value) { - return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) { - return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); - } - - template - inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; - typedef meta::tuple_types return_types; - typedef typename traits::free_args_list args_list; - // compile-time eliminate any functions that we know ahead of time are of improper arity - if (meta::find_in_pack_v, index_value...>::value) { - return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) { - return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - stack::record tracking{}; - if (!stack::stack_detail::check_types{}.check(args_list(), L, start, no_panic, tracking)) { - return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); - } - } // overload_detail - - template - inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - return overload_detail::overload_match_arity_single(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - - template - inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) { - int fxarity = lua_gettop(L) - (start - 1); - return overload_match_arity(std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - - template - inline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - // use same overload resolution matching as all other parts of the framework - return overload_match_arity::call)...>(std::forward(matchfx), L, fxarity, start, std::forward(args)...); - } - - template - inline int construct(lua_State* L) { - static const auto& meta = usertype_traits::metatable(); - int argcount = lua_gettop(L); - call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1) : call_syntax::dot; - argcount -= static_cast(syntax); - - T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); - T*& referencepointer = *pointerpointer; - T* obj = reinterpret_cast(pointerpointer + 1); - referencepointer = obj; - reference userdataref(L, -1); - userdataref.pop(); - - construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); - - userdataref.push(); - luaL_getmetatable(L, &meta[0]); - if (type_of(L, -1) == type::lua_nil) { - lua_pop(L, 1); - return luaL_error(L, "sol: unable to get usertype metatable"); - } - - lua_setmetatable(L, -2); - return 1; - } - - template - struct agnostic_lua_call_wrapper { - template - static int call(lua_State* L, Fx&& f, Args&&... args) { - typedef wrapper> wrap; - typedef typename wrap::returns_list returns_list; - typedef typename wrap::free_args_list args_list; - typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); - } - }; - - template - struct agnostic_lua_call_wrapper, true, is_variable, checked, boost, C> { - template - static int call(lua_State* L, F&& f) { - return stack::push_reference(L, detail::unwrap(f.value)); - } - }; - - template - struct agnostic_lua_call_wrapper, false, is_variable, checked, boost, C> { - template - static int call_assign(std::true_type, lua_State* L, V&& f) { - detail::unwrap(f.value) = stack::get>(L, boost + (is_variable ? 3 : 1)); - return 0; - } - - template - static int call_assign(std::false_type, lua_State* L, Args&&...) { - return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); - } - - template - static int call_const(std::false_type, lua_State* L, Args&&... args) { - typedef meta::unwrapped_t R; - return call_assign(std::is_assignable>, R>(), L, std::forward(args)...); - } - - template - static int call_const(std::true_type, lua_State* L, Args&&...) { - return luaL_error(L, "sol: cannot write to a readonly (const) variable"); - } - - template - static int call(lua_State* L, V&& f) { - return call_const(std::is_const>(), L, f); - } - }; - - template - struct agnostic_lua_call_wrapper { - static int call(lua_State* L, lua_r_CFunction f) { - return f(L); - } - }; - - template - struct agnostic_lua_call_wrapper { - static int call(lua_State* L, lua_CFunction f) { - return f(L); - } - }; - - template - struct agnostic_lua_call_wrapper { - static int call(lua_State* L, const no_prop&) { - return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property"); - } - }; - - template - struct agnostic_lua_call_wrapper { - static int call(lua_State* L, const no_construction&) { - return function_detail::no_construction_error(L); - } - }; - - template - struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { - static int call(lua_State*, const bases&) { - // Uh. How did you even call this, lul - return 0; - } - }; - - template - struct lua_call_wrapper : agnostic_lua_call_wrapper {}; - - template - struct lua_call_wrapper::value>> { - typedef wrapper> wrap; - typedef typename wrap::object_type object_type; - - template - static int call(lua_State* L, Fx&& f, object_type& o) { - typedef typename wrap::returns_list returns_list; - typedef typename wrap::args_list args_list; - typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); - } - - template - static int call(lua_State* L, Fx&& f) { - typedef std::conditional_t::value, object_type, T> Ta; -#ifdef SOL_SAFE_USERTYPE - auto maybeo = stack::check_get(L, 1); - if (!maybeo || maybeo.value() == nullptr) { - return luaL_error(L, "sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)"); - } - object_type* o = static_cast(maybeo.value()); - return call(L, std::forward(f), *o); -#else - object_type& o = static_cast(*stack::get>(L, 1)); - return call(L, std::forward(f), o); -#endif // Safety - } - }; - - template - struct lua_call_wrapper::value>> { - typedef lua_bind_traits traits_type; - typedef wrapper> wrap; - typedef typename wrap::object_type object_type; - - template - static int call_assign(std::true_type, lua_State* L, V&& f, object_type& o) { - typedef typename wrap::args_list args_list; - typedef typename wrap::caller caller; - return stack::call_into_lua(types(), args_list(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); - } - - template - static int call_assign(std::true_type, lua_State* L, V&& f) { - typedef std::conditional_t::value, object_type, T> Ta; -#ifdef SOL_SAFE_USERTYPE - auto maybeo = stack::check_get(L, 1); - if (!maybeo || maybeo.value() == nullptr) { - if (is_variable) { - return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)"); - } - return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)"); - } - object_type* o = static_cast(maybeo.value()); - return call_assign(std::true_type(), L, f, *o); -#else - object_type& o = static_cast(*stack::get>(L, 1)); - return call_assign(std::true_type(), L, f, o); -#endif // Safety - } - - template - static int call_assign(std::false_type, lua_State* L, Args&&...) { - return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); - } - - template - static int call_const(std::false_type, lua_State* L, Args&&... args) { - typedef typename traits_type::return_type R; - return call_assign(std::is_assignable>, R>(), L, std::forward(args)...); - } - - template - static int call_const(std::true_type, lua_State* L, Args&&...) { - return luaL_error(L, "sol: cannot write to a readonly (const) variable"); - } - - template - static int call(lua_State* L, V&& f) { - return call_const(std::is_const(), L, std::forward(f)); - } - - template - static int call(lua_State* L, V&& f, object_type& o) { - return call_const(std::is_const(), L, std::forward(f), o); - } - }; - - template - struct lua_call_wrapper::value>> { - typedef lua_bind_traits traits_type; - typedef wrapper> wrap; - typedef typename wrap::object_type object_type; - - template - static int call(lua_State* L, V&& f, object_type& o) { - typedef typename wrap::returns_list returns_list; - typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), std::forward(f), o); - } - - template - static int call(lua_State* L, V&& f) { - typedef std::conditional_t::value, object_type, T> Ta; -#ifdef SOL_SAFE_USERTYPE - auto maybeo = stack::check_get(L, 1); - if (!maybeo || maybeo.value() == nullptr) { - if (is_variable) { - return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); - } - return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); - } - object_type* o = static_cast(maybeo.value()); - return call(L, f, *o); -#else - object_type& o = static_cast(*stack::get>(L, 1)); - return call(L, f, o); -#endif // Safety - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { - typedef constructor_list F; - - static int call(lua_State* L, F&) { - const auto& metakey = usertype_traits::metatable(); - int argcount = lua_gettop(L); - call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1) : call_syntax::dot; - argcount -= static_cast(syntax); - - T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); - reference userdataref(L, -1); - T*& referencepointer = *pointerpointer; - T* obj = reinterpret_cast(pointerpointer + 1); - referencepointer = obj; - - construct_match(constructor_match(obj), L, argcount, boost + 1 + static_cast(syntax)); - - userdataref.push(); - luaL_getmetatable(L, &metakey[0]); - if (type_of(L, -1) == type::lua_nil) { - lua_pop(L, 1); - return luaL_error(L, "sol: unable to get usertype metatable"); - } - - lua_setmetatable(L, -2); - return 1; - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { - typedef constructor_wrapper F; - - struct onmatch { - template - int operator()(types, index_value, types r, types a, lua_State* L, int, int start, F& f) { - const auto& metakey = usertype_traits::metatable(); - T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); - reference userdataref(L, -1); - T*& referencepointer = *pointerpointer; - T* obj = reinterpret_cast(pointerpointer + 1); - referencepointer = obj; - - auto& func = std::get(f.functions); - stack::call_into_lua(r, a, L, boost + start, func, detail::implicit_wrapper(obj)); - - userdataref.push(); - luaL_getmetatable(L, &metakey[0]); - if (type_of(L, -1) == type::lua_nil) { - lua_pop(L, 1); - std::string err = "sol: unable to get usertype metatable for "; - err += usertype_traits::name(); - return luaL_error(L, err.c_str()); - } - lua_setmetatable(L, -2); - - return 1; - } - }; - - static int call(lua_State* L, F& f) { - call_syntax syntax = stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1); - int syntaxval = static_cast(syntax); - int argcount = lua_gettop(L) - syntaxval; - return construct_match>...>(onmatch(), L, argcount, 1 + syntaxval, f); - } - - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, std::enable_if_t::value>> { - typedef destructor_wrapper F; - - static int call(lua_State* L, const F&) { - return detail::usertype_alloc_destroy(L); - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, std::enable_if_t::value>> { - typedef destructor_wrapper F; - - static int call(lua_State* L, const F& f) { - T& obj = stack::get(L); - f.fx(detail::implicit_wrapper(obj)); - return 0; - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { - typedef overload_set F; - - struct on_match { - template - int operator()(types, index_value, types, types, lua_State* L, int, int, F& fx) { - auto& f = std::get(fx.functions); - return lua_call_wrapper{}.call(L, f); - } - }; - - static int call(lua_State* L, F& fx) { - return overload_match_arity(on_match(), L, lua_gettop(L), 1, fx); - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { - typedef factory_wrapper F; - - struct on_match { - template - int operator()(types, index_value, types, types, lua_State* L, int, int, F& fx) { - auto& f = std::get(fx.functions); - return lua_call_wrapper{}.call(L, f); - } - }; - - static int call(lua_State* L, F& fx) { - return overload_match_arity(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx); - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { - typedef std::conditional_t P; - typedef meta::unqualified_t

U; - typedef wrapper wrap; - typedef lua_bind_traits traits_type; - typedef meta::unqualified_t> object_type; - - template - static int self_call(std::true_type, lua_State* L, F&& f) { - // The type being void means we don't have any arguments, so it might be a free functions? - typedef typename traits_type::free_args_list args_list; - typedef typename wrap::returns_list returns_list; - typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); - } - - template - static int self_call(std::false_type, lua_State* L, F&& f) { - typedef meta::pop_front_type_t args_list; - typedef T Ta; -#ifdef SOL_SAFE_USERTYPE - auto maybeo = stack::check_get(L, 1); - if (!maybeo || maybeo.value() == nullptr) { - if (is_variable) { - return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); - } - return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); - } - object_type* o = static_cast(maybeo.value()); -#else - object_type* o = static_cast(stack::get>(L, 1)); -#endif // Safety - typedef typename wrap::returns_list returns_list; - typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o); - } - - template - static int defer_call(std::false_type, lua_State* L, F&& f, Args&&... args) { - return self_call(meta::any, meta::boolean>::value != type::userdata>>(), L, pick(meta::boolean(), f), std::forward(args)...); - } - - template - static int defer_call(std::true_type, lua_State* L, F&& f, Args&&... args) { - auto& p = pick(meta::boolean(), std::forward(f)); - return lua_call_wrapper, is_index, is_variable, checked, boost>{}.call(L, p, std::forward(args)...); - } - - template - static int call(lua_State* L, F&& f, Args&&... args) { - typedef meta::any< - std::is_void, - std::is_same, - meta::is_specialization_of, - meta::is_specialization_of, - meta::is_specialization_of, - std::is_member_pointer - > is_specialized; - return defer_call(is_specialized(), L, std::forward(f), std::forward(args)...); - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { - typedef protect_t F; - - template - static int call(lua_State* L, F& fx, Args&&... args) { - return lua_call_wrapper{}.call(L, fx.value, std::forward(args)...); - } - }; - - template - struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { - template - static int call(lua_State* L, F&& f) { - return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::get<0>(f.arguments)); - } - }; - - template - inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { - return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward(fx), std::forward(args)...); - } - - template - inline int call_user(lua_State* L) { - auto& fx = stack::get>(L, upvalue_index(1)); - return call_wrapped(L, fx); - } - - template - struct is_var_bind : std::false_type {}; - - template - struct is_var_bind::value>> : std::true_type {}; - - template <> - struct is_var_bind : std::true_type {}; - - template - struct is_var_bind> : std::true_type {}; - - template - struct is_var_bind> : std::true_type {}; - } // call_detail - - template - struct is_variable_binding : call_detail::is_var_bind> {}; - - template - struct is_function_binding : meta::neg> {}; - -} // sol - -// end of sol/call.hpp - -namespace sol { - namespace function_detail { - template - inline int call_wrapper_variable(std::false_type, lua_State* L) { - typedef meta::bind_traits> traits_type; - typedef typename traits_type::args_list args_list; - typedef meta::tuple_types return_type; - return stack::call_into_lua(return_type(), args_list(), L, 1, fx); - } - - template - inline int call_set_assignable(std::false_type, T&&, lua_State* L) { - return luaL_error(L, "cannot write to this type: copy assignment/constructor not available"); - } - - template - inline int call_set_assignable(std::true_type, lua_State* L, T&& mem) { - (mem.*variable) = stack::get(L, 2); - return 0; - } - - template - inline int call_set_variable(std::false_type, lua_State* L, T&&) { - return luaL_error(L, "cannot write to a const variable"); - } - - template - inline int call_set_variable(std::true_type, lua_State* L, T&& mem) { - return call_set_assignable(std::is_assignable, R>(), L, std::forward(mem)); - } - - template - inline int call_wrapper_variable(std::true_type, lua_State* L) { - typedef meta::bind_traits> traits_type; - typedef typename traits_type::object_type T; - typedef typename traits_type::return_type R; - auto& mem = stack::get(L, 1); - switch (lua_gettop(L)) { - case 1: { - decltype(auto) r = (mem.*variable); - stack::push_reference(L, std::forward(r)); - return 1; } - case 2: - return call_set_variable(meta::neg>(), L, mem); - default: - return luaL_error(L, "incorrect number of arguments to member variable function call"); - } - } - - template - inline int call_wrapper_function(std::false_type, lua_State* L) { - return call_wrapper_variable(std::is_member_object_pointer(), L); - } - - template - inline int call_wrapper_function(std::true_type, lua_State* L) { - return call_detail::call_wrapped(L, fx); - } - - template - int call_wrapper_entry(lua_State* L) { - return call_wrapper_function(std::is_member_function_pointer>(), L); - } - - template - struct c_call_matcher { - template - int operator()(types, index_value, types, types, lua_State* L, int, int) const { - typedef meta::at_in_pack_t target; - return target::call(L); - } - }; - - } // function_detail - - template - inline int c_call(lua_State* L) { -#ifdef __clang__ - return detail::trampoline(L, function_detail::call_wrapper_entry); -#else - return detail::static_trampoline<(&function_detail::call_wrapper_entry)>(L); -#endif // fuck you clang :c - } - - template - struct wrap { - typedef F type; - - static int call(lua_State* L) { - return c_call(L); - } - }; - - template - inline int c_call(lua_State* L) { - if (sizeof...(Fxs) < 2) { - return meta::at_in_pack_t<0, Fxs...>::call(L); - } - else { - return call_detail::overload_match_arity(function_detail::c_call_matcher(), L, lua_gettop(L), 1); - } - } - -} // sol - -// end of sol/function_types_templated.hpp - -// beginning of sol/function_types_stateless.hpp - -namespace sol { - namespace function_detail { - template - struct upvalue_free_function { - typedef std::remove_pointer_t> function_type; - typedef lua_bind_traits traits_type; - - static int real_call(lua_State* L) { - auto udata = stack::stack_detail::get_as_upvalues(L); - function_type* fx = udata.first; - return call_detail::call_wrapped(L, fx); - } - - static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); - } - - int operator()(lua_State* L) { - return call(L); - } - }; - - template - struct upvalue_member_function { - typedef std::remove_pointer_t> function_type; - typedef lua_bind_traits traits_type; - - static int real_call(lua_State* L) { - // Layout: - // idx 1...n: verbatim data of member function pointer - // idx n + 1: is the object's void pointer - // We don't need to store the size, because the other side is templated - // with the same member function pointer type - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); - auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); - function_type& memfx = memberdata.first; - auto& item = *objdata.first; - return call_detail::call_wrapped(L, memfx, item); - } - - static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); - } - - int operator()(lua_State* L) { - return call(L); - } - }; - - template - struct upvalue_member_variable { - typedef std::remove_pointer_t> function_type; - typedef lua_bind_traits traits_type; - - static int real_call(lua_State* L) { - // Layout: - // idx 1...n: verbatim data of member variable pointer - // idx n + 1: is the object's void pointer - // We don't need to store the size, because the other side is templated - // with the same member function pointer type - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); - auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); - auto& mem = *objdata.first; - function_type& var = memberdata.first; - switch (lua_gettop(L)) { - case 0: - return call_detail::call_wrapped(L, var, mem); - case 1: - return call_detail::call_wrapped(L, var, mem); - default: - return luaL_error(L, "sol: incorrect number of arguments to member variable function"); - } - } - - static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); - } - - int operator()(lua_State* L) { - return call(L); - } - }; - - template - struct upvalue_this_member_function { - typedef std::remove_pointer_t> function_type; - typedef lua_bind_traits traits_type; - - static int real_call(lua_State* L) { - // Layout: - // idx 1...n: verbatim data of member variable pointer - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); - function_type& memfx = memberdata.first; - return call_detail::call_wrapped(L, memfx); - } - - static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); - } - - int operator()(lua_State* L) { - return call(L); - } - }; - - template - struct upvalue_this_member_variable { - typedef std::remove_pointer_t> function_type; - typedef lua_bind_traits traits_type; - - static int real_call(lua_State* L) { - // Layout: - // idx 1...n: verbatim data of member variable pointer - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); - function_type& var = memberdata.first; - switch (lua_gettop(L)) { - case 1: - return call_detail::call_wrapped(L, var); - case 2: - return call_detail::call_wrapped(L, var); - default: - return luaL_error(L, "sol: incorrect number of arguments to member variable function"); - } - } - - static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); - } - - int operator()(lua_State* L) { - return call(L); - } - }; - } // function_detail -} // sol - -// end of sol/function_types_stateless.hpp - -// beginning of sol/function_types_stateful.hpp - -namespace sol { - namespace function_detail { - template - struct functor_function { - typedef meta::unwrapped_t> Function; - Function fx; - - template - functor_function(Function f, Args&&... args) : fx(std::move(f), std::forward(args)...) {} - - int call(lua_State* L) { - return call_detail::call_wrapped(L, fx); - } - - int operator()(lua_State* L) { - auto f = [&](lua_State*) -> int { return this->call(L); }; - return detail::trampoline(L, f); - } - }; - - template - struct member_function { - typedef std::remove_pointer_t> function_type; - typedef meta::function_return_t return_type; - typedef meta::function_args_t args_lists; - function_type invocation; - T member; - - template - member_function(function_type f, Args&&... args) : invocation(std::move(f)), member(std::forward(args)...) {} - - int call(lua_State* L) { - return call_detail::call_wrapped(L, invocation, detail::unwrap(detail::deref(member))); - } - - int operator()(lua_State* L) { - auto f = [&](lua_State*) -> int { return this->call(L); }; - return detail::trampoline(L, f); - } - }; - - template - struct member_variable { - typedef std::remove_pointer_t> function_type; - typedef typename meta::bind_traits::return_type return_type; - typedef typename meta::bind_traits::args_list args_lists; - function_type var; - T member; - typedef std::add_lvalue_reference_t>> M; - - template - member_variable(function_type v, Args&&... args) : var(std::move(v)), member(std::forward(args)...) {} - - int call(lua_State* L) { - M mem = detail::unwrap(detail::deref(member)); - switch (lua_gettop(L)) { - case 0: - return call_detail::call_wrapped(L, var, mem); - case 1: - return call_detail::call_wrapped(L, var, mem); - default: - return luaL_error(L, "sol: incorrect number of arguments to member variable function"); - } - } - - int operator()(lua_State* L) { - auto f = [&](lua_State*) -> int { return this->call(L); }; - return detail::trampoline(L, f); - } - }; - } // function_detail -} // sol - -// end of sol/function_types_stateful.hpp - -// beginning of sol/function_types_overloaded.hpp - -namespace sol { - namespace function_detail { - template - struct overloaded_function { - typedef std::tuple overload_list; - typedef std::make_index_sequence indices; - overload_list overloads; - - overloaded_function(overload_list set) - : overloads(std::move(set)) {} - - overloaded_function(Functions... fxs) - : overloads(fxs...) { - - } - - template - int call(types, index_value, types, types, lua_State* L, int, int) { - auto& func = std::get(overloads); - return call_detail::call_wrapped(L, func); - } - - int operator()(lua_State* L) { - auto mfx = [&](auto&&... args) { return this->call(std::forward(args)...); }; - return call_detail::overload_match(mfx, L, 1 + start_skew); - } - }; - } // function_detail -} // sol - -// end of sol/function_types_overloaded.hpp - -// beginning of sol/resolve.hpp - -namespace sol { - -#ifndef __clang__ - // constexpr is fine for not-clang - - namespace detail { - template(Args...)>> - inline constexpr auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { - using Sig = R(Args...); - typedef meta::unqualified_t Fu; - return static_cast(&Fu::operator()); - } - - template> - inline constexpr auto resolve_f(std::true_type, F&& f) - -> decltype(resolve_i(types>(), std::forward(f))) { - return resolve_i(types>(), std::forward(f)); - } - - template - inline constexpr void resolve_f(std::false_type, F&&) { - static_assert(meta::has_deducible_signature::value, - "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); - } - - template> - inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature(), std::forward(f))) { - return resolve_f(meta::has_deducible_signature {}, std::forward(f)); - } - - template> - inline constexpr auto resolve_i(types, F&& f) -> decltype(resolve_i(types(), std::forward(f))) { - return resolve_i(types(), std::forward(f)); - } - - template - inline constexpr Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) { - return mem_func_ptr; - } - - template - inline constexpr Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) { - return mem_variable_ptr; - } - } // detail - - template - inline constexpr auto resolve(R fun_ptr(Args...))->R(*)(Args...) { - return fun_ptr; - } - - template - inline constexpr Sig* resolve(Sig* fun_ptr) { - return fun_ptr; - } - - template - inline constexpr auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) { - return mem_ptr; - } - - template - inline constexpr Sig C::* resolve(Sig C::* mem_ptr) { - return detail::resolve_v(std::is_member_object_pointer(), mem_ptr); - } - - template>> = meta::enabler> - inline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { - return detail::resolve_i(types(), std::forward(f)); - } -#else - - // Clang has distinct problems with constexpr arguments, - // so don't use the constexpr versions inside of clang. - - namespace detail { - template(Args...)>> - inline auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { - using Sig = R(Args...); - typedef meta::unqualified_t Fu; - return static_cast(&Fu::operator()); - } - - template> - inline auto resolve_f(std::true_type, F&& f) - -> decltype(resolve_i(types>(), std::forward(f))) { - return resolve_i(types>(), std::forward(f)); - } - - template - inline void resolve_f(std::false_type, F&&) { - static_assert(meta::has_deducible_signature::value, - "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); - } - - template> - inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature(), std::forward(f))) { - return resolve_f(meta::has_deducible_signature {}, std::forward(f)); - } - - template> - inline auto resolve_i(types, F&& f) -> decltype(resolve_i(types(), std::forward(f))) { - return resolve_i(types(), std::forward(f)); - } - - template - inline Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) { - return mem_func_ptr; - } - - template - inline Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) { - return mem_variable_ptr; - } - } // detail - - template - inline auto resolve(R fun_ptr(Args...))->R(*)(Args...) { - return fun_ptr; - } - - template - inline Sig* resolve(Sig* fun_ptr) { - return fun_ptr; - } - - template - inline auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) { - return mem_ptr; - } - - template - inline Sig C::* resolve(Sig C::* mem_ptr) { - return detail::resolve_v(std::is_member_object_pointer(), mem_ptr); - } - - template - inline auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { - return detail::resolve_i(types(), std::forward(f)); - } - -#endif - -} // sol - -// end of sol/resolve.hpp - -namespace sol { - namespace function_detail { - template - struct class_indicator {}; - - struct call_indicator {}; - } - namespace stack { - template - struct pusher> { - template - static void select_convertible(std::false_type, types, lua_State* L, Fx&& fx, Args&&... args) { - typedef std::remove_pointer_t> clean_fx; - typedef function_detail::functor_function F; - set_fx(L, std::forward(fx), std::forward(args)...); - } - - template - static void select_convertible(std::true_type, types, lua_State* L, Fx&& fx, Args&&... args) { - using fx_ptr_t = R(*)(A...); - fx_ptr_t fxptr = detail::unwrap(std::forward(fx)); - select_function(std::true_type(), L, fxptr, std::forward(args)...); - } - - template - static void select_convertible(types t, lua_State* L, Fx&& fx, Args&&... args) { - typedef std::decay_t> raw_fx_t; - typedef R(*fx_ptr_t)(A...); - typedef std::is_convertible is_convertible; - select_convertible(is_convertible(), t, L, std::forward(fx), std::forward(args)...); - } - - template - static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { - typedef meta::function_signature_t> Sig; - select_convertible(types(), L, std::forward(fx), std::forward(args)...); - } - - template - static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::remove_pointer_t> clean_fx; - typedef function_detail::member_variable, clean_fx> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::decay_t dFx; - dFx memfxptr(std::forward(fx)); - auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t>::call; - - int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); - upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_convertible(types(), L, std::forward(fx), std::forward(args)...); - } - - template >> = meta::enabler> - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef meta::boolean>::value || std::is_pointer::value> is_reference; - select_reference_member_variable(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { - typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::decay_t clean_fx; - typedef function_detail::member_function, clean_fx> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::decay_t dFx; - dFx memfxptr(std::forward(fx)); - auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t>::call; - - int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); - upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_variable(std::is_member_object_pointer>(), L, std::forward(fx), std::forward(args)...); - } - - template >> = meta::enabler> - static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef meta::boolean>::value || std::is_pointer::value> is_reference; - select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { - typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_function(std::is_member_function_pointer>(), L, std::forward(fx), std::forward(args)...); - } - - template - static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { - std::decay_t target(std::forward(fx), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_free_function::call; - - int upvalues = stack::stack_detail::push_as_upvalues(L, target); - stack::push(L, c_closure(freefunc, upvalues)); - } - - static void select_function(std::true_type, lua_State* L, lua_CFunction f) { - stack::push(L, f); - } - - template - static void select(lua_State* L, Fx&& fx, Args&&... args) { - select_function(std::is_function>(), L, std::forward(fx), std::forward(args)...); - } - - template - static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call>; - - stack::push>(L, std::forward(args)...); - stack::push(L, c_closure(freefunc, 1)); - } - - template - static int push(lua_State* L, Args&&... args) { - // Set will always place one thing (function) on the stack - select(L, std::forward(args)...); - return 1; - } - }; - - template - struct pusher> { - template - static int push_func(std::index_sequence, lua_State* L, FP&& fp) { - return stack::push(L, detail::forward_get(fp.arguments)...); - } - - static int push(lua_State* L, const function_arguments& fp) { - return push_func(std::make_index_sequence(), L, fp); - } - - static int push(lua_State* L, function_arguments&& fp) { - return push_func(std::make_index_sequence(), L, std::move(fp)); - } - }; - - template - struct pusher> { - static int push(lua_State* L, std::function fx) { - return pusher>{}.push(L, std::move(fx)); - } - }; - - template - struct pusher::value>> { - template - static int push(lua_State* L, F&& f, Args&&... args) { - return pusher>{}.push(L, std::forward(f), std::forward(args)...); - } - }; - - template - struct pusher, meta::neg>, meta::neg>>>::value>> { - template - static int push(lua_State* L, F&& f) { - return pusher>{}.push(L, std::forward(f)); - } - }; - - template - struct pusher> { - static int push(lua_State* L, overload_set&& set) { - typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, std::move(set.functions)); - return 1; - } - - static int push(lua_State* L, const overload_set& set) { - typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, set.functions); - return 1; - } - }; - - template - struct pusher> { - static int push(lua_State* L, protect_t&& pw) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, std::move(pw.value)); - return stack::push(L, c_closure(cf, closures)); - } - - static int push(lua_State* L, const protect_t& pw) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, pw.value); - return stack::push(L, c_closure(cf, closures)); - } - }; - - template - struct pusher, std::enable_if_t::value && !std::is_void::value>> { - static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, sol::overload(std::move(pw.read), std::move(pw.write))); - } - static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, sol::overload(pw.read, pw.write)); - } - }; - - template - struct pusher> { - static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, std::move(pw.read)); - } - static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, pw.read); - } - }; - - template - struct pusher> { - static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, std::move(pw.write)); - } - static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, pw.write); - } - }; - - template - struct pusher> { - static int push(lua_State* L, var_wrapper&& vw) { - return stack::push(L, std::move(vw.value)); - } - static int push(lua_State* L, const var_wrapper& vw) { - return stack::push(L, vw.value); - } - }; - - template - struct pusher> { - static int push(lua_State* L, const factory_wrapper& fw) { - typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, fw.functions); - return 1; - } - - static int push(lua_State* L, factory_wrapper&& fw) { - typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, std::move(fw.functions)); - return 1; - } - - static int push(lua_State* L, const factory_wrapper& set, function_detail::call_indicator) { - typedef function_detail::overloaded_function<1, Functions...> F; - pusher>{}.set_fx(L, set.functions); - return 1; - } - - static int push(lua_State* L, factory_wrapper&& set, function_detail::call_indicator) { - typedef function_detail::overloaded_function<1, Functions...> F; - pusher>{}.set_fx(L, std::move(set.functions)); - return 1; - } - }; - - template <> - struct pusher { - static int push(lua_State* L, no_construction) { - lua_CFunction cf = &function_detail::no_construction_error; - return stack::push(L, cf); - } - - static int push(lua_State* L, no_construction c, function_detail::call_indicator) { - return push(L, c); - } - }; - - template - struct pusher>> { - static int push(lua_State* L, detail::tagged>) { - lua_CFunction cf = call_detail::construct; - return stack::push(L, cf); - } - }; - - template - struct pusher>> { - template - static int push(lua_State* L, C&& c) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, std::forward(c)); - return stack::push(L, c_closure(cf, closures)); - } - }; - - template - struct pusher>> { - static int push(lua_State* L, destructor_wrapper) { - lua_CFunction cf = detail::usertype_alloc_destroy; - return stack::push(L, cf); - } - }; - - template - struct pusher>> { - static int push(lua_State* L, destructor_wrapper c) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>(L, std::move(c)); - return stack::push(L, c_closure(cf, closures)); - } - }; - - } // stack -} // sol - -// end of sol/function_types.hpp - -namespace sol { - template - class basic_function : public base_t { - private: - void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const { - lua_callk(base_t::lua_state(), static_cast(argcount), static_cast(resultcount), 0, nullptr); - } - - template - auto invoke(types, std::index_sequence, std::ptrdiff_t n) const { - luacall(n, lua_size>::value); - return stack::pop>(base_t::lua_state()); - } - - template - Ret invoke(types, std::index_sequence, std::ptrdiff_t n) const { - luacall(n, lua_size::value); - return stack::pop(base_t::lua_state()); - } - - template - void invoke(types, std::index_sequence, std::ptrdiff_t n) const { - luacall(n, 0); - } - - function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const { - int stacksize = lua_gettop(base_t::lua_state()); - int firstreturn = (std::max)(1, stacksize - static_cast(n)); - luacall(n, LUA_MULTRET); - int poststacksize = lua_gettop(base_t::lua_state()); - int returncount = poststacksize - (firstreturn - 1); - return function_result(base_t::lua_state(), firstreturn, returncount); - } - - public: - basic_function() = default; - template , basic_function>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_function(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_function>::value) { - auto pp = stack::push_pop(*this); - stack::check(base_t::lua_state(), -1, type_panic); - } -#endif // Safety - } - basic_function(const basic_function&) = default; - basic_function& operator=(const basic_function&) = default; - basic_function(basic_function&&) = default; - basic_function& operator=(basic_function&&) = default; - basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {} - basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {} - template >>, meta::neg>> = meta::enabler> - basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {} - basic_function(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(L, index, type_panic); -#endif // Safety - } - basic_function(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - stack::check(L, -1, type_panic); -#endif // Safety - } - - template - function_result operator()(Args&&... args) const { - return call<>(std::forward(args)...); - } - - template - decltype(auto) operator()(types, Args&&... args) const { - return call(std::forward(args)...); - } - - template - decltype(auto) call(Args&&... args) const { - base_t::push(); - int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward(args)...); - return invoke(types(), std::make_index_sequence(), pushcount); - } - }; - - namespace stack { - template - struct getter> { - typedef meta::bind_traits fx_t; - typedef typename fx_t::args_list args_lists; - typedef meta::tuple_types return_types; - - template - static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [f, L, index](Args&&... args) -> meta::return_type_t { - return f.call(std::forward(args)...); - }; - return std::move(fx); - } - - template - static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [f, L, index](FxArgs&&... args) -> void { - f(std::forward(args)...); - }; - return std::move(fx); - } - - template - static std::function get_std_func(types<>, types t, lua_State* L, int index) { - return get_std_func(types(), t, L, index); - } - - static std::function get(lua_State* L, int index, record& tracking) { - tracking.last = 1; - tracking.used += 1; - type t = type_of(L, index); - if (t == type::none || t == type::lua_nil) { - return nullptr; - } - return get_std_func(return_types(), args_lists(), L, index); - } - }; - } // stack -} // sol - -// end of sol/function.hpp - -// beginning of sol/protected_function.hpp - -// beginning of sol/protected_function_result.hpp - -namespace sol { - struct protected_function_result : public proxy_base { - private: - lua_State* L; - int index; - int returncount; - int popcount; - call_status err; - - template - decltype(auto) tagged_get(types>) const { - if (!valid()) { - return sol::optional(nullopt); - } - return stack::get>(L, index); - } - - template - decltype(auto) tagged_get(types) const { -#ifdef SOL_CHECK_ARGUMENTS - if (!valid()) { - type_panic(L, index, type_of(L, index), type::none); - } -#endif // Check Argument Safety - return stack::get(L, index); - } - - optional tagged_get(types>) const { - if (valid()) { - return nullopt; - } - return error(detail::direct_error, stack::get(L, index)); - } - - error tagged_get(types) const { -#ifdef SOL_CHECK_ARGUMENTS - if (valid()) { - type_panic(L, index, type_of(L, index), type::none); - } -#endif // Check Argument Safety - return error(detail::direct_error, stack::get(L, index)); - } - - public: - protected_function_result() = default; - protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept : L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) { - - } - protected_function_result(const protected_function_result&) = default; - protected_function_result& operator=(const protected_function_result&) = default; - protected_function_result(protected_function_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but we will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = call_status::runtime; - } - protected_function_result& operator=(protected_function_result&& o) noexcept { - L = o.L; - index = o.index; - returncount = o.returncount; - popcount = o.popcount; - err = o.err; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but we will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = call_status::runtime; - return *this; - } - - call_status status() const noexcept { - return err; - } - - bool valid() const noexcept { - return status() == call_status::ok || status() == call_status::yielded; - } - - template - decltype(auto) get() const { - return tagged_get(types>()); - } - - lua_State* lua_state() const noexcept { return L; }; - int stack_index() const noexcept { return index; }; - - ~protected_function_result() { - stack::remove(L, index, popcount); - } - }; -} // sol - -// end of sol/protected_function_result.hpp - -#include - -namespace sol { - namespace detail { - inline reference& handler_storage() { - static sol::reference h; - return h; - } - - struct handler { - const reference& target; - int stackindex; - handler(const reference& target) : target(target), stackindex(0) { - if (target.valid()) { - stackindex = lua_gettop(target.lua_state()) + 1; - target.push(); - } - } - bool valid() const { return stackindex != 0; } - ~handler() { - if (valid()) { - lua_remove(target.lua_state(), stackindex); - } - } - }; - } - - template - class basic_protected_function : public base_t { - public: - static reference& get_default_handler() { - return detail::handler_storage(); - } - - static void set_default_handler(const reference& ref) { - detail::handler_storage() = ref; - } - - static void set_default_handler(reference&& ref) { - detail::handler_storage() = std::move(ref); - } - - private: - call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler& h) const { - return static_cast(lua_pcallk(base_t::lua_state(), static_cast(argcount), static_cast(resultcount), h.stackindex, 0, nullptr)); - } - - template - auto invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { - luacall(n, sizeof...(Ret), h); - return stack::pop>(base_t::lua_state()); - } - - template - Ret invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { - luacall(n, 1, h); - return stack::pop(base_t::lua_state()); - } - - template - void invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { - luacall(n, 0, h); - } - - protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler& h) const { - int stacksize = lua_gettop(base_t::lua_state()); - int poststacksize = stacksize; - int firstreturn = 1; - int returncount = 0; - call_status code = call_status::ok; -#ifndef SOL_NO_EXCEPTIONS - auto onexcept = [&](const char* error) { - h.stackindex = 0; - if (h.target.valid()) { - h.target.push(); - stack::push(base_t::lua_state(), error); - lua_call(base_t::lua_state(), 1, 1); - } - else { - stack::push(base_t::lua_state(), error); - } - }; - try { -#endif // No Exceptions - firstreturn = (std::max)(1, static_cast(stacksize - n - static_cast(h.valid()))); - code = luacall(n, LUA_MULTRET, h); - poststacksize = lua_gettop(base_t::lua_state()) - static_cast(h.valid()); - returncount = poststacksize - (firstreturn - 1); -#ifndef SOL_NO_EXCEPTIONS - } - // Handle C++ errors thrown from C++ functions bound inside of lua - catch (const char* error) { - onexcept(error); - firstreturn = lua_gettop(base_t::lua_state()); - return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime); - } - catch (const std::exception& error) { - onexcept(error.what()); - firstreturn = lua_gettop(base_t::lua_state()); - return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime); - } - catch (...) { - onexcept("caught (...) unknown error during protected_function call"); - firstreturn = lua_gettop(base_t::lua_state()); - return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime); - } -#endif // No Exceptions - return protected_function_result(base_t::lua_state(), firstreturn, returncount, returncount, code); - } - - public: - reference error_handler; - - basic_protected_function() = default; - template , basic_protected_function>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_protected_function(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_function>::value) { - auto pp = stack::push_pop(*this); - stack::check(base_t::lua_state(), -1, type_panic); - } -#endif // Safety - } - basic_protected_function(const basic_protected_function&) = default; - basic_protected_function& operator=(const basic_protected_function&) = default; - basic_protected_function(basic_protected_function&&) = default; - basic_protected_function& operator=(basic_protected_function&&) = default; - basic_protected_function(const basic_function& b, reference eh = get_default_handler()) : base_t(b), error_handler(std::move(eh)) {} - basic_protected_function(basic_function&& b, reference eh = get_default_handler()) : base_t(std::move(b)), error_handler(std::move(eh)) {} - basic_protected_function(const stack_reference& r, reference eh = get_default_handler()) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} - basic_protected_function(stack_reference&& r, reference eh = get_default_handler()) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} - template - basic_protected_function(proxy_base&& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function(), std::move(eh)) {} - template - basic_protected_function(const proxy_base& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function(), std::move(eh)) {} - template >>, meta::neg>> = meta::enabler> - basic_protected_function(lua_State* L, T&& r, reference eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {} - basic_protected_function(lua_State* L, int index = -1, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(L, index, type_panic); -#endif // Safety - } - basic_protected_function(lua_State* L, ref_index index, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - stack::check(L, -1, type_panic); -#endif // Safety - } - - template - protected_function_result operator()(Args&&... args) const { - return call<>(std::forward(args)...); - } - - template - decltype(auto) operator()(types, Args&&... args) const { - return call(std::forward(args)...); - } - - template - decltype(auto) call(Args&&... args) const { - detail::handler h(error_handler); - base_t::push(); - int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward(args)...); - return invoke(types(), std::make_index_sequence(), pushcount, h); - } - }; -} // sol - -// end of sol/protected_function.hpp - -namespace sol { - struct stack_proxy : public proxy_base { - private: - lua_State* L; - int index; - - public: - stack_proxy() : L(nullptr), index(0) {} - stack_proxy(lua_State* L, int index) : L(L), index(index) {} - - template - decltype(auto) get() const { - return stack::get(L, stack_index()); - } - - int push() const { - return push(L); - } - - int push(lua_State* Ls) const { - lua_pushvalue(Ls, index); - return 1; - } - - lua_State* lua_state() const { return L; } - int stack_index() const { return index; } - - template - decltype(auto) call(Args&&... args) { - return get().template call(std::forward(args)...); - } - - template - decltype(auto) operator()(Args&&... args) { - return call<>(std::forward(args)...); - } - }; - - namespace stack { - template <> - struct getter { - static stack_proxy get(lua_State* L, int index = -1) { - return stack_proxy(L, index); - } - }; - - template <> - struct pusher { - static int push(lua_State*, const stack_proxy& ref) { - return ref.push(); - } - }; - } // stack - - namespace detail { - template <> - struct is_speshul : std::true_type {}; - template <> - struct is_speshul : std::true_type {}; - - template - stack_proxy get(types, index_value<0>, index_value, const T& fr) { - return stack_proxy(fr.lua_state(), static_cast(fr.stack_index() + I)); - } - - template 0)>> = meta::enabler> - stack_proxy get(types, index_value, index_value, const T& fr) { - return get(types(), index_value(), index_value::value>(), fr); - } - } - - template <> - struct tie_size : std::integral_constant {}; - - template - stack_proxy get(const function_result& fr) { - return stack_proxy(fr.lua_state(), static_cast(fr.stack_index() + I)); - } - - template - stack_proxy get(types t, const function_result& fr) { - return detail::get(t, index_value(), index_value<0>(), fr); - } - - template <> - struct tie_size : std::integral_constant {}; - - template - stack_proxy get(const protected_function_result& fr) { - return stack_proxy(fr.lua_state(), static_cast(fr.stack_index() + I)); - } - - template - stack_proxy get(types t, const protected_function_result& fr) { - return detail::get(t, index_value(), index_value<0>(), fr); - } -} // sol - -// end of sol/stack_proxy.hpp - -#include -#include - -namespace sol { - template - struct va_iterator : std::iterator, std::ptrdiff_t, std::conditional_t, std::conditional_t> { - typedef std::iterator, std::ptrdiff_t, std::conditional_t, std::conditional_t> base_t; - typedef typename base_t::reference reference; - typedef typename base_t::pointer pointer; - typedef typename base_t::value_type value_type; - typedef typename base_t::difference_type difference_type; - typedef typename base_t::iterator_category iterator_category; - lua_State* L; - int index; - int stacktop; - stack_proxy sp; - - va_iterator() : L(nullptr), index((std::numeric_limits::max)()), stacktop((std::numeric_limits::max)()) {} - va_iterator(lua_State* luastate, int idx, int topidx) : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {} - - reference operator*() { - return stack_proxy(L, index); - } - - pointer operator->() { - sp = stack_proxy(L, index); - return &sp; - } - - va_iterator& operator++ () { - ++index; - return *this; - } - - va_iterator operator++ (int) { - auto r = *this; - this->operator ++(); - return r; - } - - va_iterator& operator-- () { - --index; - return *this; - } - - va_iterator operator-- (int) { - auto r = *this; - this->operator --(); - return r; - } - - va_iterator& operator+= (difference_type idx) { - index += static_cast(idx); - return *this; - } - - va_iterator& operator-= (difference_type idx) { - index -= static_cast(idx); - return *this; - } - - difference_type operator- (const va_iterator& r) const { - return index - r.index; - } - - va_iterator operator+ (difference_type idx) const { - va_iterator r = *this; - r += idx; - return r; - } - - reference operator[](difference_type idx) { - return stack_proxy(L, index + static_cast(idx)); - } - - bool operator==(const va_iterator& r) const { - if (stacktop == (std::numeric_limits::max)()) { - return r.index == r.stacktop; - } - else if (r.stacktop == (std::numeric_limits::max)()) { - return index == stacktop; - } - return index == r.index; - } - - bool operator != (const va_iterator& r) const { - return !(this->operator==(r)); - } - - bool operator < (const va_iterator& r) const { - return index < r.index; - } - - bool operator > (const va_iterator& r) const { - return index > r.index; - } - - bool operator <= (const va_iterator& r) const { - return index <= r.index; - } - - bool operator >= (const va_iterator& r) const { - return index >= r.index; - } - }; - - template - inline va_iterator operator+(typename va_iterator::difference_type n, const va_iterator& r) { - return r + n; - } - - struct variadic_args { - private: - lua_State* L; - int index; - int stacktop; - - public: - typedef stack_proxy reference_type; - typedef stack_proxy value_type; - typedef stack_proxy* pointer; - typedef std::ptrdiff_t difference_type; - typedef std::size_t size_type; - typedef va_iterator iterator; - typedef va_iterator const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - variadic_args() = default; - variadic_args(lua_State* luastate, int stackindex = -1) : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {} - variadic_args(const variadic_args&) = default; - variadic_args& operator=(const variadic_args&) = default; - variadic_args(variadic_args&& o) : L(o.L), index(o.index), stacktop(o.stacktop) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.stacktop = 0; - } - variadic_args& operator=(variadic_args&& o) { - L = o.L; - index = o.index; - stacktop = o.stacktop; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.stacktop = 0; - return *this; - } - - iterator begin() { return iterator(L, index, stacktop + 1); } - iterator end() { return iterator(L, stacktop + 1, stacktop + 1); } - const_iterator begin() const { return const_iterator(L, index, stacktop + 1); } - const_iterator end() const { return const_iterator(L, stacktop + 1, stacktop + 1); } - const_iterator cbegin() const { return begin(); } - const_iterator cend() const { return end(); } - - reverse_iterator rbegin() { return std::reverse_iterator(begin()); } - reverse_iterator rend() { return std::reverse_iterator(end()); } - const_reverse_iterator rbegin() const { return std::reverse_iterator(begin()); } - const_reverse_iterator rend() const { return std::reverse_iterator(end()); } - const_reverse_iterator crbegin() const { return std::reverse_iterator(cbegin()); } - const_reverse_iterator crend() const { return std::reverse_iterator(cend()); } - - int push() const { - return push(L); - } - - int push(lua_State* target) const { - int pushcount = 0; - for (int i = index; i <= stacktop; ++i) { - lua_pushvalue(L, i); - pushcount += 1; - } - if (target != L) { - lua_xmove(L, target, pushcount); - } - return pushcount; - } - - template - decltype(auto) get(difference_type start = 0) const { - return stack::get(L, index + static_cast(start)); - } - - stack_proxy operator[](difference_type start) const { - return stack_proxy(L, index + static_cast(start)); - } - - lua_State* lua_state() const { return L; }; - int stack_index() const { return index; }; - int leftover_count() const { return stacktop - (index - 1); } - int top() const { return stacktop; } - }; - - namespace stack { - template <> - struct getter { - static variadic_args get(lua_State* L, int index, record& tracking) { - tracking.last = 0; - return variadic_args(L, index); - } - }; - - template <> - struct pusher { - static int push(lua_State* L, const variadic_args& ref) { - return ref.push(L); - } - }; - } // stack -} // sol - -// end of sol/variadic_args.hpp - -namespace sol { - - template ::value, typename T> - R make_reference(lua_State* L, T&& value) { - int backpedal = stack::push(L, std::forward(value)); - R r = stack::get(L, -backpedal); - if (should_pop) { - lua_pop(L, backpedal); - } - return r; - } - - template ::value, typename... Args> - R make_reference(lua_State* L, Args&&... args) { - int backpedal = stack::push(L, std::forward(args)...); - R r = stack::get(L, -backpedal); - if (should_pop) { - lua_pop(L, backpedal); - } - return r; - } - - template - class basic_object : public basic_object_base { - private: - typedef basic_object_base base_t; - - template - basic_object(std::integral_constant, lua_State* L, int index = -1) noexcept : base_t(L, index) { - if (invert_and_pop) { - lua_pop(L, -index); - } - } - - public: - basic_object() noexcept = default; - template , basic_object>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_object(T&& r) : base_t(std::forward(r)) {} - basic_object(lua_nil_t r) : base_t(r) {} - basic_object(const basic_object&) = default; - basic_object(basic_object&&) = default; - basic_object(const stack_reference& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {} - basic_object(stack_reference&& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {} - template - basic_object(const proxy_base& r) noexcept : basic_object(r.operator basic_object()) {} - template - basic_object(proxy_base&& r) noexcept : basic_object(r.operator basic_object()) {} - basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {} - basic_object(lua_State* L, ref_index index) noexcept : base_t(L, index) {} - template - basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) {} - template - basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place, std::forward(arg), std::forward(args)...) {} - basic_object& operator=(const basic_object&) = default; - basic_object& operator=(basic_object&&) = default; - basic_object& operator=(const base_type& b) { base_t::operator=(b); return *this; } - basic_object& operator=(base_type&& b) { base_t::operator=(std::move(b)); return *this; } - template - basic_object& operator=(const proxy_base& r) { this->operator=(r.operator basic_object()); return *this; } - template - basic_object& operator=(proxy_base&& r) { this->operator=(r.operator basic_object()); return *this; } - }; - - template - object make_object(lua_State* L, T&& value) { - return make_reference(L, std::forward(value)); - } - - template - object make_object(lua_State* L, Args&&... args) { - return make_reference(L, std::forward(args)...); - } -} // sol - -// end of sol/object.hpp - -namespace sol { - template - struct proxy : public proxy_base> { - private: - typedef meta::condition, Key, std::tuple>, Key&, meta::unqualified_t>>> key_type; - - template - decltype(auto) tuple_get(std::index_sequence) const { - return tbl.template traverse_get(std::get(key)...); - } - - template - void tuple_set(std::index_sequence, T&& value) { - tbl.traverse_set(std::get(key)..., std::forward(value)); - } - - public: - Table tbl; - key_type key; - - template - proxy(Table table, T&& k) : tbl(table), key(std::forward(k)) {} - - template - proxy& set(T&& item) { - tuple_set(std::make_index_sequence>::value>(), std::forward(item)); - return *this; - } - - template - proxy& set_function(Args&&... args) { - tbl.set_function(key, std::forward(args)...); - return *this; - } - - template>>, meta::is_callable>> = meta::enabler> - proxy& operator=(U&& other) { - return set_function(std::forward(other)); - } - - template>>, meta::is_callable>> = meta::enabler> - proxy& operator=(U&& other) { - return set(std::forward(other)); - } - - template - decltype(auto) get() const { - return tuple_get(std::make_index_sequence>::value>()); - } - - template - decltype(auto) get_or(T&& otherwise) const { - typedef decltype(get()) U; - sol::optional option = get>(); - if (option) { - return static_cast(option.value()); - } - return static_cast(std::forward(otherwise)); - } - - template - decltype(auto) get_or(D&& otherwise) const { - sol::optional option = get>(); - if (option) { - return static_cast(option.value()); - } - return static_cast(std::forward(otherwise)); - } - - template - decltype(auto) operator[](K&& k) const { - auto keys = meta::tuplefy(key, std::forward(k)); - return proxy(tbl, std::move(keys)); - } - - template - decltype(auto) call(Args&&... args) { - return get().template call(std::forward(args)...); - } - - template - decltype(auto) operator()(Args&&... args) { - return call<>(std::forward(args)...); - } - - bool valid() const { - auto pp = stack::push_pop(tbl); - auto p = stack::probe_get_field, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state())); - lua_pop(tbl.lua_state(), p.levels); - return p; - } - }; - - template - inline bool operator==(T&& left, const proxy& right) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator==(const proxy& right, T&& left) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator!=(T&& left, const proxy& right) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator!=(const proxy& right, T&& left) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; - } - - template - inline bool operator==(lua_nil_t, const proxy& right) { - return !right.valid(); - } - - template - inline bool operator==(const proxy& right, lua_nil_t) { - return !right.valid(); - } - - template - inline bool operator!=(lua_nil_t, const proxy& right) { - return right.valid(); - } - - template - inline bool operator!=(const proxy& right, lua_nil_t) { - return right.valid(); - } - - namespace stack { - template - struct pusher> { - static int push(lua_State* L, const proxy& p) { - sol::reference r = p; - return r.push(L); - } - }; - } // stack -} // sol - -// end of sol/proxy.hpp - -// beginning of sol/usertype.hpp - -// beginning of sol/usertype_metatable.hpp - -// beginning of sol/deprecate.hpp - -#ifndef SOL_DEPRECATED - #ifdef _MSC_VER - #define SOL_DEPRECATED __declspec(deprecated) - #elif __GNUC__ - #define SOL_DEPRECATED __attribute__((deprecated)) - #else - #define SOL_DEPRECATED [[deprecated]] - #endif // compilers -#endif // SOL_DEPRECATED - -namespace sol { - namespace detail { - template - struct SOL_DEPRECATED deprecate_type { - using type = T; - }; - } // detail -} // sol - -// end of sol/deprecate.hpp - -#include -#include - -namespace sol { - namespace usertype_detail { - typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&); - typedef int(*member_search)(lua_State*, void*, int); - - struct call_information { - member_search index; - member_search new_index; - int runtime_target; - - call_information(member_search index, member_search newindex) : call_information(index, newindex, -1) {} - call_information(member_search index, member_search newindex, int runtimetarget) : index(index), new_index(newindex), runtime_target(runtimetarget) {} - }; - - typedef std::unordered_map mapping_t; - - struct variable_wrapper { - virtual int index(lua_State* L) = 0; - virtual int new_index(lua_State* L) = 0; - virtual ~variable_wrapper() {}; - }; - - template - struct callable_binding : variable_wrapper { - F fx; - - template - callable_binding(Arg&& arg) : fx(std::forward(arg)) {} - - virtual int index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); - } - - virtual int new_index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); - } - }; - - typedef std::unordered_map> variable_map; - typedef std::unordered_map function_map; - - struct simple_map { - const char* metakey; - variable_map variables; - function_map functions; - base_walk indexbaseclasspropogation; - base_walk newindexbaseclasspropogation; - - simple_map(const char* mkey, base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} - }; - } - - struct usertype_metatable_core { - usertype_detail::mapping_t mapping; - lua_CFunction indexfunc; - lua_CFunction newindexfunc; - std::vector runtime; - bool mustindex; - - usertype_metatable_core(lua_CFunction ifx, lua_CFunction nifx) : - mapping(), indexfunc(ifx), - newindexfunc(nifx), runtime(), mustindex(false) - { - - } - - usertype_metatable_core(const usertype_metatable_core&) = default; - usertype_metatable_core(usertype_metatable_core&&) = default; - usertype_metatable_core& operator=(const usertype_metatable_core&) = default; - usertype_metatable_core& operator=(usertype_metatable_core&&) = default; - - }; - - namespace usertype_detail { - const lua_Integer toplevel_magic = static_cast(0x00020001); - - struct add_destructor_tag {}; - struct check_destructor_tag {}; - struct verified_tag {} const verified{}; - - template - struct is_non_factory_constructor : std::false_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template <> - struct is_non_factory_constructor : std::true_type {}; - - template - struct is_constructor : is_non_factory_constructor {}; - - template - struct is_constructor> : std::true_type {}; - - template - using has_constructor = meta::any>...>; - - template - struct is_destructor : std::false_type {}; - - template - struct is_destructor> : std::true_type {}; - - template - using has_destructor = meta::any>...>; - - struct no_comp { - template - bool operator()(A&&, B&&) const { - return false; - } - }; - - inline bool is_indexer(string_detail::string_shim s) { - return s == to_string(meta_function::index) || s == to_string(meta_function::new_index); - } - - inline bool is_indexer(meta_function mf) { - return mf == meta_function::index || mf == meta_function::new_index; - } - - inline bool is_indexer(call_construction) { - return false; - } - - inline bool is_indexer(base_classes_tag) { - return false; - } - - inline auto make_shim(string_detail::string_shim s) { - return s; - } - - inline auto make_shim(call_construction) { - return string_detail::string_shim(to_string(meta_function::call_function)); - } - - inline auto make_shim(meta_function mf) { - return string_detail::string_shim(to_string(mf)); - } - - inline auto make_shim(base_classes_tag) { - return string_detail::string_shim(detail::base_class_cast_key()); - } - - template - inline std::string make_string(Arg&& arg) { - string_detail::string_shim s = make_shim(arg); - return std::string(s.c_str(), s.size()); - } - - template - inline luaL_Reg make_reg(N&& n, lua_CFunction f) { - luaL_Reg l{ make_shim(std::forward(n)).c_str(), f }; - return l; - } - - struct registrar { - registrar() = default; - registrar(const registrar&) = default; - registrar(registrar&&) = default; - registrar& operator=(const registrar&) = default; - registrar& operator=(registrar&&) = default; - virtual int push_um(lua_State* L) = 0; - virtual ~registrar() {} - }; - - inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(2)); - std::vector& runtime = umc.runtime; - object& runtimeobj = runtime[runtimetarget]; - return stack::push(L, runtimeobj); - } - - template - inline int indexing_fail(lua_State* L) { - if (is_index) { -#if 0//def SOL_SAFE_USERTYPE - auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); - string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); - return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); -#else - int isnum = 0; - lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum); - if (isnum != 0 && magic == toplevel_magic) { - if (lua_getmetatable(L, 1) == 1) { - int metatarget = lua_gettop(L); - stack::get_field(L, stack_reference(L, raw_index(2)), metatarget); - return 1; - } - } - // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... - return stack::push(L, lua_nil); -#endif - } - else { - auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); - string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); - return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); - } - } - - int runtime_new_index(lua_State* L, void*, int runtimetarget); - - template - inline int metatable_newindex(lua_State* L) { - int isnum = 0; - lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum); - if (isnum != 0 && magic == toplevel_magic) { - auto non_indexable = [&L]() { - if (is_simple) { - simple_map& sm = stack::get>(L, upvalue_index(1)); - function_map& functions = sm.functions; - sol::optional maybeaccessor = stack::get>(L, 2); - if (!maybeaccessor) { - return; - } - std::string& accessor = maybeaccessor.value(); - auto preexistingit = functions.find(accessor); - if (preexistingit == functions.cend()) { - functions.emplace_hint(preexistingit, std::move(accessor), sol::object(L, 3)); - } - else { - preexistingit->second = sol::object(L, 3); - } - return; - } - usertype_metatable_core& umc = stack::get>(L, upvalue_index(2)); - bool mustindex = umc.mustindex; - if (!mustindex) - return; - sol::optional maybeaccessor = stack::get>(L, 2); - if (!maybeaccessor) { - return; - } - std::string& accessor = maybeaccessor.value(); - mapping_t& mapping = umc.mapping; - std::vector& runtime = umc.runtime; - int target = static_cast(runtime.size()); - auto preexistingit = mapping.find(accessor); - if (preexistingit == mapping.cend()) { - runtime.emplace_back(L, 3); - mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_new_index, target)); - } - else { - target = preexistingit->second.runtime_target; - runtime[target] = sol::object(L, 3); - preexistingit->second = call_information(&runtime_object_call, &runtime_new_index, target); - } - }; - non_indexable(); - for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) { - const char* metakey = nullptr; - switch (i) { - case 0: - metakey = &usertype_traits::metatable()[0]; - luaL_getmetatable(L, metakey); - break; - case 1: - metakey = &usertype_traits>::metatable()[0]; - luaL_getmetatable(L, metakey); - break; - case 2: - metakey = &usertype_traits::metatable()[0]; - luaL_getmetatable(L, metakey); - break; - case 3: - default: - metakey = &usertype_traits::user_metatable()[0]; - { - luaL_getmetatable(L, metakey); - lua_getmetatable(L, -1); - } - break; - } - int tableindex = lua_gettop(L); - if (type_of(L, tableindex) == type::lua_nil) { - continue; - } - stack::set_field(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex); - } - lua_settop(L, 0); - return 0; - } - return indexing_fail(L); - } - - inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { - usertype_metatable_core& umc = stack::get>(L, upvalue_index(2)); - std::vector& runtime = umc.runtime; - object& runtimeobj = runtime[runtimetarget]; - runtimeobj = object(L, 3); - return 0; - } - - template - static void walk_single_base(lua_State* L, bool& found, int& ret, string_detail::string_shim&) { - if (found) - return; - const char* metakey = &usertype_traits::metatable()[0]; - const char* gcmetakey = &usertype_traits::gc_table()[0]; - const char* basewalkkey = is_index ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key(); - - luaL_getmetatable(L, metakey); - if (type_of(L, -1) == type::lua_nil) { - lua_pop(L, 1); - return; - } - - stack::get_field(L, basewalkkey); - if (type_of(L, -1) == type::lua_nil) { - lua_pop(L, 2); - return; - } - lua_CFunction basewalkfunc = stack::pop(L); - lua_pop(L, 1); - - stack::get_field(L, gcmetakey); - int value = basewalkfunc(L); - if (value > -1) { - found = true; - ret = value; - } - } - - template - static void walk_all_bases(lua_State* L, bool& found, int& ret, string_detail::string_shim& accessor) { - (void)L; - (void)found; - (void)ret; - (void)accessor; - (void)detail::swallow{ 0, (walk_single_base(L, found, ret, accessor), 0)... }; - } - - template - inline int operator_wrap(lua_State* L) { - auto maybel = stack::check_get(L, 1); - if (maybel) { - auto mayber = stack::check_get(L, 2); - if (mayber) { - auto& l = *maybel; - auto& r = *mayber; - if (std::is_same::value) { - return stack::push(L, detail::ptr(l) == detail::ptr(r)); - } - else { - Op op; - return stack::push(L, (detail::ptr(l) == detail::ptr(r)) || op(detail::deref(l), detail::deref(r))); - } - } - } - return stack::push(L, false); - } - - template = meta::enabler> - inline void make_reg_op(Regs& l, int& index, const char* name) { - l[index] = { name, &operator_wrap }; - ++index; - } - - template = meta::enabler> - inline void make_reg_op(Regs&, int&, const char*) { - // Do nothing if there's no support - } - } // usertype_detail - - template - struct clean_type { - typedef std::conditional_t>::value, T&, std::decay_t> type; - }; - - template - using clean_type_t = typename clean_type::type; - - template - struct usertype_metatable : usertype_detail::registrar {}; - - template - struct usertype_metatable, Tn...> : usertype_metatable_core, usertype_detail::registrar { - typedef std::make_index_sequence indices; - typedef std::index_sequence half_indices; - typedef std::array regs_t; - typedef std::tuple RawTuple; - typedef std::tuple ...> Tuple; - template - struct check_binding : is_variable_binding> {}; - Tuple functions; - lua_CFunction destructfunc; - lua_CFunction callconstructfunc; - lua_CFunction indexbase; - lua_CFunction newindexbase; - usertype_detail::base_walk indexbaseclasspropogation; - usertype_detail::base_walk newindexbaseclasspropogation; - void* baseclasscheck; - void* baseclasscast; - bool secondarymeta; - bool hasequals; - bool hasless; - bool haslessequals; - - template >> = meta::enabler> - lua_CFunction make_func() const { - return std::get(functions); - } - - template >> = meta::enabler> - lua_CFunction make_func() const { - const auto& name = std::get(functions); - return (usertype_detail::make_shim(name) == "__newindex") ? &call : &call; - } - - static bool contains_variable() { - typedef meta::any...> has_variables; - return has_variables::value; - } - - bool contains_index() const { - bool idx = false; - (void)detail::swallow{ 0, ((idx |= usertype_detail::is_indexer(std::get(functions))), 0) ... }; - return idx; - } - - int finish_regs(regs_t& l, int& index) { - if (!hasless) { - const char* name = to_string(meta_function::less_than).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less>(l, index, name); - } - if (!haslessequals) { - const char* name = to_string(meta_function::less_than_or_equal_to).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less_equal>(l, index, name); - } - if (!hasequals) { - const char* name = to_string(meta_function::equal_to).c_str(); - usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name); - } - if (destructfunc != nullptr) { - l[index] = { to_string(meta_function::garbage_collect).c_str(), destructfunc }; - ++index; - } - return index; - } - - template - void make_regs(regs_t&, int&, call_construction, F&&) { - callconstructfunc = call; - secondarymeta = true; - } - - template - void make_regs(regs_t&, int&, base_classes_tag, bases) { - static_assert(!meta::any_same::value, "base classes cannot list the original class as part of the bases"); - if (sizeof...(Bases) < 1) { - return; - } - mustindex = true; - (void)detail::swallow{ 0, ((detail::has_derived::value = true), 0)... }; - - static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = (void*)&detail::inheritance::type_check; - baseclasscast = (void*)&detail::inheritance::type_cast; - indexbaseclasspropogation = usertype_detail::walk_all_bases; - newindexbaseclasspropogation = usertype_detail::walk_all_bases; - } - - template , base_classes_tag, call_construction>::value>> - void make_regs(regs_t& l, int& index, N&& n, F&&) { - if (is_variable_binding>::value) { - return; - } - luaL_Reg reg = usertype_detail::make_reg(std::forward(n), make_func()); - // Returnable scope - // That would be a neat keyword for C++ - // returnable { ... }; - if (reg.name == to_string(meta_function::equal_to)) { - hasequals = true; - } - if (reg.name == to_string(meta_function::less_than)) { - hasless = true; - } - if (reg.name == to_string(meta_function::less_than_or_equal_to)) { - haslessequals = true; - } - if (reg.name == to_string(meta_function::garbage_collect)) { - destructfunc = reg.func; - return; - } - else if (reg.name == to_string(meta_function::index)) { - indexfunc = reg.func; - mustindex = true; - return; - } - else if (reg.name == to_string(meta_function::new_index)) { - newindexfunc = reg.func; - mustindex = true; - return; - } - l[index] = reg; - ++index; - } - - template > - usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), - functions(std::forward(args)...), - destructfunc(nullptr), callconstructfunc(nullptr), - indexbase(&core_indexing_call), newindexbase(&core_indexing_call), - indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(usertype_detail::walk_all_bases), - baseclasscheck(nullptr), baseclasscast(nullptr), - secondarymeta(contains_variable()), - hasequals(false), hasless(false), haslessequals(false) { - std::initializer_list ilist{ { - std::pair( usertype_detail::make_string(std::get(functions)), - usertype_detail::call_information(&usertype_metatable::real_find_call, - &usertype_metatable::real_find_call) - ) - }... }; - this->mapping.insert(ilist); - for (const auto& n : meta_function_names()) { - this->mapping.erase(n); - } - this->mustindex = contains_variable() || contains_index(); - } - - usertype_metatable(const usertype_metatable&) = default; - usertype_metatable(usertype_metatable&&) = default; - usertype_metatable& operator=(const usertype_metatable&) = default; - usertype_metatable& operator=(usertype_metatable&&) = default; - - template - static int real_find_call(lua_State* L, void* um, int) { - auto& f = *static_cast(um); - if (is_variable_binding(f.functions))>::value) { - return real_call_with(L, f); - } - int upvalues = stack::push(L, light(f)); - auto cfunc = &call; - return stack::push(L, c_closure(cfunc, upvalues)); - } - - template - static int real_meta_call(lua_State* L, void* um, int) { - auto& f = *static_cast(um); - return is_index ? f.indexfunc(L) : f.newindexfunc(L); - } - - template - static int core_indexing_call(lua_State* L) { - usertype_metatable& f = toplevel ? stack::get>(L, upvalue_index(1)) : stack::pop>(L); - static const int keyidx = -2 + static_cast(is_index); - if (toplevel && stack::get(L, keyidx) != type::string) { - return is_index ? f.indexfunc(L) : f.newindexfunc(L); - } - std::string name = stack::get(L, keyidx); - auto memberit = f.mapping.find(name); - if (memberit != f.mapping.cend()) { - const usertype_detail::call_information& ci = memberit->second; - const usertype_detail::member_search& member = is_index ? ci.index: ci.new_index; - return (member)(L, static_cast(&f), ci.runtime_target); - } - string_detail::string_shim accessor = name; - int ret = 0; - bool found = false; - // Otherwise, we need to do propagating calls through the bases - if (is_index) - f.indexbaseclasspropogation(L, found, ret, accessor); - else - f.newindexbaseclasspropogation(L, found, ret, accessor); - if (found) { - return ret; - } - return toplevel ? (is_index ? f.indexfunc(L) : f.newindexfunc(L)) : -1; - } - - static int real_index_call(lua_State* L) { - return core_indexing_call(L); - } - - static int real_new_index_call(lua_State* L) { - return core_indexing_call(L); - } - - template - static int real_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, upvalue_index(1)); - return real_call_with(L, f); - } - - template - static int real_call_with(lua_State* L, usertype_metatable& um) { - typedef meta::unqualified_tuple_element_t K; - typedef meta::unqualified_tuple_element_t F; - static const int boost = - !usertype_detail::is_non_factory_constructor::value - && std::is_same::value ? - 1 : 0; - auto& f = std::get(um.functions); - return call_detail::call_wrapped(L, f); - } - - template - static int call(lua_State* L) { - return detail::static_trampoline<(&real_call)>(L); - } - - template - static int call_with(lua_State* L) { - return detail::static_trampoline<(&real_call_with)>(L); - } - - static int index_call(lua_State* L) { - return detail::static_trampoline<(&real_index_call)>(L); - } - - static int new_index_call(lua_State* L) { - return detail::static_trampoline<(&real_new_index_call)>(L); - } - - virtual int push_um(lua_State* L) override { - return stack::push(L, std::move(*this)); - } - - ~usertype_metatable() override { - - } - }; - - namespace stack { - - template - struct pusher, Args...>> { - typedef usertype_metatable, Args...> umt_t; - typedef typename umt_t::regs_t regs_t; - - static umt_t& make_cleanup(lua_State* L, umt_t&& umx) { - // ensure some sort of uniqueness - static int uniqueness = 0; - std::string uniquegcmetakey = usertype_traits::user_gc_metatable(); - // std::to_string doesn't exist in android still, with NDK, so this bullshit - // is necessary - // thanks, Android :v - int appended = snprintf(nullptr, 0, "%d", uniqueness); - std::size_t insertionpoint = uniquegcmetakey.length() - 1; - uniquegcmetakey.append(appended, '\0'); - char* uniquetarget = &uniquegcmetakey[insertionpoint]; - snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness); - ++uniqueness; - - const char* gcmetakey = &usertype_traits::gc_table()[0]; - // Make sure userdata's memory is properly in lua first, - // otherwise all the light userdata we make later will become invalid - stack::push>(L, metatable_key, uniquegcmetakey, std::move(umx)); - // Create the top level thing that will act as our deleter later on - stack_reference umt(L, -1); - stack::set_field(L, gcmetakey, umt); - umt.pop(); - - stack::get_field(L, gcmetakey); - return stack::pop>(L); - } - - static int push(lua_State* L, umt_t&& umx) { - - umt_t& um = make_cleanup(L, std::move(umx)); - usertype_metatable_core& umc = um; - regs_t value_table{ {} }; - int lastreg = 0; - (void)detail::swallow{ 0, (um.template make_regs<(I * 2)>(value_table, lastreg, std::get<(I * 2)>(um.functions), std::get<(I * 2 + 1)>(um.functions)), 0)... }; - um.finish_regs(value_table, lastreg); - value_table[lastreg] = { nullptr, nullptr }; - regs_t ref_table = value_table; - regs_t unique_table = value_table; - bool hasdestructor = !value_table.empty() && to_string(meta_function::garbage_collect) == value_table[lastreg - 1].name; - if (hasdestructor) { - ref_table[lastreg - 1] = { nullptr, nullptr }; - unique_table[lastreg - 1] = { value_table[lastreg - 1].name, detail::unique_destruct }; - } - - // Now use um - const bool& mustindex = umc.mustindex; - for (std::size_t i = 0; i < 3; ++i) { - // Pointer types, AKA "references" from C++ - const char* metakey = nullptr; - luaL_Reg* metaregs = nullptr; - switch (i) { - case 0: - metakey = &usertype_traits::metatable()[0]; - metaregs = ref_table.data(); - break; - case 1: - metakey = &usertype_traits>::metatable()[0]; - metaregs = unique_table.data(); - break; - case 2: - default: - metakey = &usertype_traits::metatable()[0]; - metaregs = value_table.data(); - break; - } - luaL_newmetatable(L, metakey); - stack_reference t(L, -1); - stack::push(L, make_light(um)); - luaL_setfuncs(L, metaregs, 1); - - if (um.baseclasscheck != nullptr) { - stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index()); - } - if (um.baseclasscast != nullptr) { - stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index()); - } - - stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, make_light(um), make_light(umc)), t.stack_index()); - stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um), make_light(umc)), t.stack_index()); - - if (mustindex) { - // Basic index pushing: specialize - // index and newindex to give variables and stuff - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(umc)), t.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(umc)), t.stack_index()); - } - else { - // If there's only functions, we can use the fast index version - stack::set_field(L, meta_function::index, t, t.stack_index()); - } - // metatable on the metatable - // for call constructor purposes and such - lua_createtable(L, 0, 3); - stack_reference metabehind(L, -1); - if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um), make_light(umc)), metabehind.stack_index()); - } - if (um.secondarymeta) { - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(umc)), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(umc)), metabehind.stack_index()); - } - stack::set_field(L, metatable_key, metabehind, t.stack_index()); - metabehind.pop(); - // We want to just leave the table - // in the registry only, otherwise we return it - t.pop(); - } - - // Now for the shim-table that actually gets assigned to the name - luaL_newmetatable(L, &usertype_traits::user_metatable()[0]); - stack_reference t(L, -1); - stack::push(L, make_light(um)); - luaL_setfuncs(L, value_table.data(), 1); - { - lua_createtable(L, 0, 3); - stack_reference metabehind(L, -1); - if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um), make_light(umc)), metabehind.stack_index()); - } - - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um), make_light(umc), 0, usertype_detail::toplevel_magic), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um), make_light(umc), 0, usertype_detail::toplevel_magic), metabehind.stack_index()); - - stack::set_field(L, metatable_key, metabehind, t.stack_index()); - metabehind.pop(); - } - - return 1; - } - }; - - } // stack - -} // sol - -// end of sol/usertype_metatable.hpp - -// beginning of sol/simple_usertype_metatable.hpp - -namespace sol { - - namespace usertype_detail { - template - inline int simple_core_indexing_call(lua_State* L) { - simple_map& sm = toplevel ? stack::get>(L, upvalue_index(1)) : stack::pop>(L); - variable_map& variables = sm.variables; - function_map& functions = sm.functions; - static const int keyidx = -2 + static_cast(is_index); - if (toplevel) { - if (stack::get(L, keyidx) != type::string) { - lua_CFunction indexingfunc = is_index ? stack::get(L, upvalue_index(2)) : stack::get(L, upvalue_index(3)); - return indexingfunc(L); - } - } - string_detail::string_shim accessor = stack::get(L, keyidx); - std::string accessorkey = accessor.c_str(); - auto vit = variables.find(accessorkey); - if (vit != variables.cend()) { - auto& varwrap = *(vit->second); - if (is_index) { - return varwrap.index(L); - } - return varwrap.new_index(L); - } - auto fit = functions.find(accessorkey); - if (fit != functions.cend()) { - sol::object& func = fit->second; - if (is_index) { - return stack::push(L, func); - } - else { - lua_CFunction indexingfunc = is_index ? stack::get(L, upvalue_index(2)) : stack::get(L, upvalue_index(3)); - return indexingfunc(L); - } - } - // Check table storage first for a method that works - luaL_getmetatable(L, sm.metakey); - if (type_of(L, -1) != type::lua_nil) { - stack::get_field(L, accessor.c_str(), lua_gettop(L)); - if (type_of(L, -1) != type::lua_nil) { - // Woo, we found it? - lua_remove(L, -2); - return 1; - } - lua_pop(L, 1); - } - lua_pop(L, 1); - - int ret = 0; - bool found = false; - // Otherwise, we need to do propagating calls through the bases - if (is_index) { - sm.indexbaseclasspropogation(L, found, ret, accessor); - } - else { - sm.newindexbaseclasspropogation(L, found, ret, accessor); - } - if (found) { - return ret; - } - if (toplevel) { - lua_CFunction indexingfunc = is_index ? stack::get(L, upvalue_index(2)) : stack::get(L, upvalue_index(3)); - return indexingfunc(L); - } - return -1; - } - - inline int simple_real_index_call(lua_State* L) { - return simple_core_indexing_call(L); - } - - inline int simple_real_new_index_call(lua_State* L) { - return simple_core_indexing_call(L); - } - - inline int simple_index_call(lua_State* L) { - return detail::static_trampoline<(&simple_real_index_call)>(L); - } - - inline int simple_new_index_call(lua_State* L) { - return detail::static_trampoline<(&simple_real_new_index_call)>(L); - } - } - - struct simple_tag {} const simple{}; - - template - struct simple_usertype_metatable : usertype_detail::registrar { - public: - usertype_detail::function_map registrations; - usertype_detail::variable_map varmap; - object callconstructfunc; - lua_CFunction indexfunc; - lua_CFunction newindexfunc; - lua_CFunction indexbase; - lua_CFunction newindexbase; - usertype_detail::base_walk indexbaseclasspropogation; - usertype_detail::base_walk newindexbaseclasspropogation; - void* baseclasscheck; - void* baseclasscast; - bool mustindex; - bool secondarymeta; - - template - void insert(N&& n, object&& o) { - std::string key = usertype_detail::make_string(std::forward(n)); - auto hint = registrations.find(key); - if (hint == registrations.cend()) { - registrations.emplace_hint(hint, std::move(key), std::move(o)); - return; - } - hint->second = std::move(o); - } - - template - void insert_prepare(std::true_type, lua_State* L, N&&, F&& f, Args&&... args) { - object o = make_object(L, std::forward(f), function_detail::call_indicator(), std::forward(args)...); - callconstructfunc = std::move(o); - } - - template - void insert_prepare(std::false_type, lua_State* L, N&& n, F&& f, Args&&... args) { - object o = make_object(L, std::forward(f), std::forward(args)...); - insert(std::forward(n), std::move(o)); - } - - template - void add_member_function(std::true_type, lua_State* L, N&& n, F&& f) { - insert_prepare(std::is_same, call_construction>(), L, std::forward(n), std::forward(f), function_detail::class_indicator()); - } - - template - void add_member_function(std::false_type, lua_State* L, N&& n, F&& f) { - insert_prepare(std::is_same, call_construction>(), L, std::forward(n), std::forward(f)); - } - - template >> = meta::enabler> - void add_function(lua_State* L, N&& n, F&& f) { - object o = make_object(L, as_function_reference(std::forward(f))); - if (std::is_same, call_construction>::value) { - callconstructfunc = std::move(o); - return; - } - insert(std::forward(n), std::move(o)); - } - - template >> = meta::enabler> - void add_function(lua_State* L, N&& n, F&& f) { - add_member_function(std::is_member_pointer>(), L, std::forward(n), std::forward(f)); - } - - template >> = meta::enabler> - void add(lua_State* L, N&& n, F&& f) { - add_function(L, std::forward(n), std::forward(f)); - } - - template >> = meta::enabler> - void add(lua_State*, N&& n, F&& f) { - mustindex = true; - secondarymeta = true; - std::string key = usertype_detail::make_string(std::forward(n)); - auto o = std::make_unique>>(std::forward(f)); - auto hint = varmap.find(key); - if (hint == varmap.cend()) { - varmap.emplace_hint(hint, std::move(key), std::move(o)); - return; - } - hint->second = std::move(o); - } - - template - void add(lua_State* L, N&& n, constructor_wrapper c) { - object o(L, in_place>>, std::move(c)); - if (std::is_same, call_construction>::value) { - callconstructfunc = std::move(o); - return; - } - insert(std::forward(n), std::move(o)); - } - - template - void add(lua_State* L, N&& n, constructor_list c) { - object o(L, in_place>>, std::move(c)); - if (std::is_same, call_construction>::value) { - callconstructfunc = std::move(o); - return; - } - insert(std::forward(n), std::move(o)); - } - - template - void add(lua_State* L, N&& n, destructor_wrapper c) { - object o(L, in_place>>, std::move(c)); - if (std::is_same, call_construction>::value) { - callconstructfunc = std::move(o); - return; - } - insert(std::forward(n), std::move(o)); - } - - template - void add(lua_State* L, N&& n, destructor_wrapper c) { - object o(L, in_place>>, std::move(c)); - if (std::is_same, call_construction>::value) { - callconstructfunc = std::move(o); - return; - } - insert(std::forward(n), std::move(o)); - } - - template - void add(lua_State*, base_classes_tag, bases) { - static_assert(sizeof(usertype_detail::base_walk) <= sizeof(void*), "size of function pointer is greater than sizeof(void*); cannot work on this platform. Please file a bug report."); - static_assert(!meta::any_same::value, "base classes cannot list the original class as part of the bases"); - if (sizeof...(Bases) < 1) { - return; - } - mustindex = true; - (void)detail::swallow{ 0, ((detail::has_derived::value = true), 0)... }; - - static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); - static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: Please file a bug report."); - baseclasscheck = (void*)&detail::inheritance::type_check; - baseclasscast = (void*)&detail::inheritance::type_cast; - indexbaseclasspropogation = usertype_detail::walk_all_bases; - newindexbaseclasspropogation = usertype_detail::walk_all_bases; - } - - private: - template - simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) - : callconstructfunc(lua_nil), - indexfunc(&usertype_detail::indexing_fail), newindexfunc(&usertype_detail::metatable_newindex), - indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), - indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(&usertype_detail::walk_all_bases), - baseclasscheck(nullptr), baseclasscast(nullptr), - mustindex(false), secondarymeta(false) { - (void)detail::swallow{ 0, - (add(L, detail::forward_get(args), detail::forward_get(args)),0)... - }; - } - - template - simple_usertype_metatable(lua_State* L, usertype_detail::verified_tag v, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence(), L, std::forward_as_tuple(std::forward(args)...)) {} - - template - simple_usertype_metatable(lua_State* L, usertype_detail::add_destructor_tag, Args&&... args) : simple_usertype_metatable(L, usertype_detail::verified, std::forward(args)..., "__gc", default_destructor) {} - - template - simple_usertype_metatable(lua_State* L, usertype_detail::check_destructor_tag, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} - - public: - simple_usertype_metatable(lua_State* L) : simple_usertype_metatable(L, meta::condition>, decltype(default_constructor), usertype_detail::check_destructor_tag>()) {} - - template, - usertype_detail::verified_tag, - usertype_detail::add_destructor_tag, - usertype_detail::check_destructor_tag - >, - meta::is_specialization_of>, - meta::is_specialization_of> - > = meta::enabler> - simple_usertype_metatable(lua_State* L, Arg&& arg, Args&&... args) : simple_usertype_metatable(L, meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(arg), std::forward(args)...) {} - - template - simple_usertype_metatable(lua_State* L, constructors constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} - - template - simple_usertype_metatable(lua_State* L, constructor_wrapper constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} - - simple_usertype_metatable(const simple_usertype_metatable&) = default; - simple_usertype_metatable(simple_usertype_metatable&&) = default; - simple_usertype_metatable& operator=(const simple_usertype_metatable&) = default; - simple_usertype_metatable& operator=(simple_usertype_metatable&&) = default; - - virtual int push_um(lua_State* L) override { - return stack::push(L, std::move(*this)); - } - }; - - namespace stack { - template - struct pusher> { - typedef simple_usertype_metatable umt_t; - - static usertype_detail::simple_map& make_cleanup(lua_State* L, umt_t& umx) { - static int uniqueness = 0; - std::string uniquegcmetakey = usertype_traits::user_gc_metatable(); - // std::to_string doesn't exist in android still, with NDK, so this bullshit - // is necessary - // thanks, Android :v - int appended = snprintf(nullptr, 0, "%d", uniqueness); - std::size_t insertionpoint = uniquegcmetakey.length() - 1; - uniquegcmetakey.append(appended, '\0'); - char* uniquetarget = &uniquegcmetakey[insertionpoint]; - snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness); - ++uniqueness; - - const char* gcmetakey = &usertype_traits::gc_table()[0]; - stack::push>(L, metatable_key, uniquegcmetakey, &usertype_traits::metatable()[0], - umx.indexbaseclasspropogation, umx.newindexbaseclasspropogation, - std::move(umx.varmap), std::move(umx.registrations) - ); - stack_reference stackvarmap(L, -1); - stack::set_field(L, gcmetakey, stackvarmap); - stackvarmap.pop(); - - stack::get_field(L, gcmetakey); - usertype_detail::simple_map& varmap = stack::pop>(L); - return varmap; - } - - static int push(lua_State* L, umt_t&& umx) { - auto& varmap = make_cleanup(L, umx); - bool hasequals = false; - bool hasless = false; - bool haslessequals = false; - auto register_kvp = [&](std::size_t i, stack_reference& t, const std::string& first, object& second) { - if (first == to_string(meta_function::equal_to)) { - hasequals = true; - } - else if (first == to_string(meta_function::less_than)) { - hasless = true; - } - else if (first == to_string(meta_function::less_than_or_equal_to)) { - haslessequals = true; - } - else if (first == to_string(meta_function::index)) { - umx.indexfunc = second.template as(); - } - else if (first == to_string(meta_function::new_index)) { - umx.newindexfunc = second.template as(); - } - switch (i) { - case 0: - if (first == to_string(meta_function::garbage_collect)) { - return; - } - break; - case 1: - if (first == to_string(meta_function::garbage_collect)) { - stack::set_field(L, first, detail::unique_destruct, t.stack_index()); - return; - } - break; - case 2: - default: - break; - } - stack::set_field(L, first, second, t.stack_index()); - }; - for (std::size_t i = 0; i < 3; ++i) { - // Pointer types, AKA "references" from C++ - const char* metakey = nullptr; - switch (i) { - case 0: - metakey = &usertype_traits::metatable()[0]; - break; - case 1: - metakey = &usertype_traits>::metatable()[0]; - break; - case 2: - default: - metakey = &usertype_traits::metatable()[0]; - break; - } - luaL_newmetatable(L, metakey); - stack_reference t(L, -1); - for (auto& kvp : varmap.functions) { - auto& first = std::get<0>(kvp); - auto& second = std::get<1>(kvp); - register_kvp(i, t, first, second); - } - luaL_Reg opregs[4]{}; - int opregsindex = 0; - if (!hasless) { - const char* name = to_string(meta_function::less_than).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less>(opregs, opregsindex, name); - } - if (!haslessequals) { - const char* name = to_string(meta_function::less_than_or_equal_to).c_str(); - usertype_detail::make_reg_op, meta::supports_op_less_equal>(opregs, opregsindex, name); - } - if (!hasequals) { - const char* name = to_string(meta_function::equal_to).c_str(); - usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name); - } - t.push(); - luaL_setfuncs(L, opregs, 0); - t.pop(); - - if (umx.baseclasscheck != nullptr) { - stack::set_field(L, detail::base_class_check_key(), umx.baseclasscheck, t.stack_index()); - } - if (umx.baseclasscast != nullptr) { - stack::set_field(L, detail::base_class_cast_key(), umx.baseclasscast, t.stack_index()); - } - - // Base class propagation features - stack::set_field(L, detail::base_class_index_propogation_key(), umx.indexbase, t.stack_index()); - stack::set_field(L, detail::base_class_new_index_propogation_key(), umx.newindexbase, t.stack_index()); - - if (umx.mustindex) { - // use indexing function - stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc - ), t.stack_index()); - stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc - ), t.stack_index()); - } - else { - // Metatable indexes itself - stack::set_field(L, meta_function::index, t, t.stack_index()); - } - // metatable on the metatable - // for call constructor purposes and such - lua_createtable(L, 0, 2 * static_cast(umx.secondarymeta) + static_cast(umx.callconstructfunc.valid())); - stack_reference metabehind(L, -1); - if (umx.callconstructfunc.valid()) { - stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); - } - if (umx.secondarymeta) { - stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc - ), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc - ), metabehind.stack_index()); - } - stack::set_field(L, metatable_key, metabehind, t.stack_index()); - metabehind.pop(); - - t.pop(); - } - - // Now for the shim-table that actually gets pushed - luaL_newmetatable(L, &usertype_traits::user_metatable()[0]); - stack_reference t(L, -1); - for (auto& kvp : varmap.functions) { - auto& first = std::get<0>(kvp); - auto& second = std::get<1>(kvp); - register_kvp(2, t, first, second); - } - { - lua_createtable(L, 0, 2 + static_cast(umx.callconstructfunc.valid())); - stack_reference metabehind(L, -1); - if (umx.callconstructfunc.valid()) { - stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); - } - // use indexing function - stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc, - usertype_detail::toplevel_magic - ), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc, - usertype_detail::toplevel_magic - ), metabehind.stack_index()); - stack::set_field(L, metatable_key, metabehind, t.stack_index()); - metabehind.pop(); - } - - // Don't pop the table when we're done; - // return it - return 1; - } - }; - } // stack -} // sol - -// end of sol/simple_usertype_metatable.hpp - -// beginning of sol/container_usertype_metatable.hpp - -namespace sol { - - namespace detail { - - template - struct has_find { - private: - typedef std::array one; - typedef std::array two; - - template static one test(decltype(&C::find)); - template static two test(...); - - public: - static const bool value = sizeof(test(0)) == sizeof(char); - }; - - template - struct has_push_back { - private: - typedef std::array one; - typedef std::array two; - - template static one test(decltype(std::declval().push_back(std::declval>()))*); - template static two test(...); - - public: - static const bool value = sizeof(test(0)) == sizeof(char); - }; - - template - struct has_clear { - private: - typedef std::array one; - typedef std::array two; - - template static one test(decltype(&C::clear)); - template static two test(...); - - public: - static const bool value = sizeof(test(0)) == sizeof(char); - }; - - template - struct has_insert { - private: - typedef std::array one; - typedef std::array two; - - template static one test(decltype(std::declval().insert(std::declval>(), std::declval>()))*); - template static two test(...); - - public: - static const bool value = sizeof(test(0)) == sizeof(char); - }; - - template - T& get_first(const T& t) { - return std::forward(t); - } - - template - decltype(auto) get_first(const std::pair& t) { - return t.first; - } - - template >> = meta::enabler> - auto find(C& c, I&& i) { - return c.find(std::forward(i)); - } - - template >> = meta::enabler> - auto find(C& c, I&& i) { - using std::begin; - using std::end; - return std::find_if(begin(c), end(c), [&i](auto&& x) { - return i == get_first(x); - }); - } - - } - - template - struct container_usertype_metatable { - typedef meta::has_key_value_pair> is_associative; - typedef meta::unqualified_t T; - typedef typename T::iterator I; - typedef std::conditional_t> KV; - typedef typename KV::first_type K; - typedef typename KV::second_type V; - typedef std::remove_reference_t())> IR; - - struct iter { - T& source; - I it; - - iter(T& source, I it) : source(source), it(std::move(it)) {} - }; - - static auto& get_src(lua_State* L) { -#ifdef SOL_SAFE_USERTYPE - auto p = stack::check_get(L, 1); - if (!p || p.value() == nullptr) { - luaL_error(L, "sol: 'self' argument is not the proper type (pass 'self' as first argument with ':' or call on proper type)"); - } - return *p.value(); -#else - return stack::get(L, 1); -#endif // Safe getting with error - } - - static int real_index_call_associative(std::true_type, lua_State* L) { - auto k = stack::check_get(L, 2); - if (k) { - auto& src = get_src(L); - using std::end; - auto it = detail::find(src, *k); - if (it != end(src)) { - auto& v = *it; - return stack::push_reference(L, v.second); - } - } - else { - auto maybename = stack::check_get(L, 2); - if (maybename) { - auto& name = *maybename; - if (name == "add") { - return stack::push(L, &add_call); - } - else if (name == "insert") { - return stack::push(L, &insert_call); - } - else if (name == "clear") { - return stack::push(L, &clear_call); - } - } - } - return stack::push(L, lua_nil); - } - - static int real_index_call_associative(std::false_type, lua_State* L) { - auto& src = get_src(L); - auto maybek = stack::check_get(L, 2); - if (maybek) { - using std::begin; - auto it = begin(src); - K k = *maybek; - if (k > src.size() || k < 1) { - return stack::push(L, lua_nil); - } - --k; - std::advance(it, k); - return stack::push_reference(L, *it); - } - else { - auto maybename = stack::check_get(L, 2); - if (maybename) { - auto& name = *maybename; - if (name == "add") { - return stack::push(L, &add_call); - } - else if (name == "insert") { - return stack::push(L, &insert_call); - } - else if (name == "clear") { - return stack::push(L, &clear_call); - } - } - } - - return stack::push(L, lua_nil); - } - - static int real_index_call(lua_State* L) { - return real_index_call_associative(is_associative(), L); - } - - static int real_new_index_call_const(std::false_type, std::false_type, lua_State* L) { - return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)"); - } - - static int real_new_index_call_const(std::false_type, std::true_type, lua_State* L) { - return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)"); - } - - static int real_new_index_call_const(std::true_type, std::true_type, lua_State* L) { - auto& src = get_src(L); - auto k = stack::check_get(L, 2); - if (k) { - using std::end; - auto it = detail::find(src, *k); - if (it != end(src)) { - auto& v = *it; - v.second = stack::get(L, 3); - } - else { - src.insert(it, { std::move(*k), stack::get(L, 3) }); - } - } - return 0; - } - - static int real_new_index_call_const(std::true_type, std::false_type, lua_State* L) { - auto& src = get_src(L); -#ifdef SOL_SAFE_USERTYPE - auto maybek = stack::check_get(L, 2); - if (!maybek) { - return 0; - } - K k = *maybek; -#else - K k = stack::get(L, 2); -#endif - using std::begin; - auto it = begin(src); - --k; - if (k == src.size()) { - real_add_call_push(std::integral_constant::value>(), L, src, 1); - return 0; - } - std::advance(it, k); - *it = stack::get(L, 3); - return 0; - } - - static int real_new_index_call(lua_State* L) { - return real_new_index_call_const(meta::neg, std::is_const>>(), is_associative(), L); - } - - static int real_pairs_next_call_assoc(std::true_type, lua_State* L) { - using std::end; - iter& i = stack::get>(L, 1); - auto& source = i.source; - auto& it = i.it; - if (it == end(source)) { - return 0; - } - int p = stack::multi_push_reference(L, it->first, it->second); - std::advance(it, 1); - return p; - } - - static int real_pairs_call_assoc(std::true_type, lua_State* L) { - auto& src = get_src(L); - using std::begin; - stack::push(L, pairs_next_call); - stack::push>(L, src, begin(src)); - stack::push(L, 1); - return 3; - } - - static int real_pairs_next_call_assoc(std::false_type, lua_State* L) { - using std::end; - iter& i = stack::get>(L, 1); - auto& source = i.source; - auto& it = i.it; - K k = stack::get(L, 2); - if (it == end(source)) { - return 0; - } - int p = stack::multi_push_reference(L, k + 1, *it); - std::advance(it, 1); - return p; - } - - static int real_pairs_call_assoc(std::false_type, lua_State* L) { - auto& src = get_src(L); - using std::begin; - stack::push(L, pairs_next_call); - stack::push>(L, src, begin(src)); - stack::push(L, 0); - return 3; - } - - static int real_pairs_next_call(lua_State* L) { - return real_pairs_next_call_assoc(is_associative(), L); - } - - static int real_pairs_call(lua_State* L) { - return real_pairs_call_assoc(is_associative(), L); - } - - static int real_length_call(lua_State*L) { - auto& src = get_src(L); - return stack::push(L, src.size()); - } - - static int real_add_call_insert(std::true_type, lua_State*L, T& src, int boost = 0) { - using std::end; - src.insert(end(src), stack::get(L, 2 + boost)); - return 0; - } - - static int real_add_call_insert(std::false_type, lua_State*L, T&, int = 0) { - static const std::string& s = detail::demangle(); - return luaL_error(L, "sol: cannot call insert on type %s", s.c_str()); - } - - static int real_add_call_push(std::true_type, lua_State*L, T& src, int boost = 0) { - src.push_back(stack::get(L, 2 + boost)); - return 0; - } - - static int real_add_call_push(std::false_type, lua_State*L, T& src, int boost = 0) { - return real_add_call_insert(std::integral_constant::value>(), L, src, boost); - } - - static int real_add_call_associative(std::true_type, lua_State* L) { - return real_insert_call(L); - } - - static int real_add_call_associative(std::false_type, lua_State* L) { - auto& src = get_src(L); - return real_add_call_push(std::integral_constant::value>(), L, src); - } - - static int real_add_call_capable(std::true_type, lua_State* L) { - return real_add_call_associative(is_associative(), L); - } - - static int real_add_call_capable(std::false_type, lua_State* L) { - static const std::string& s = detail::demangle(); - return luaL_error(L, "sol: cannot call add on type %s", s.c_str()); - } - - static int real_add_call(lua_State* L) { - return real_add_call_capable(std::integral_constant::value || detail::has_insert::value>(), L); - } - - static int real_insert_call_capable(std::false_type, std::false_type, lua_State*L) { - static const std::string& s = detail::demangle(); - return luaL_error(L, "sol: cannot call insert on type %s", s.c_str()); - } - - static int real_insert_call_capable(std::false_type, std::true_type, lua_State*L) { - return real_insert_call_capable(std::false_type(), std::false_type(), L); - } - - static int real_insert_call_capable(std::true_type, std::false_type, lua_State* L) { - using std::begin; - auto& src = get_src(L); - src.insert(std::next(begin(src), stack::get(L, 2)), stack::get(L, 3)); - return 0; - } - - static int real_insert_call_capable(std::true_type, std::true_type, lua_State* L) { - return real_new_index_call(L); - } - - static int real_insert_call(lua_State*L) { - return real_insert_call_capable(std::integral_constant::value>(), is_associative(), L); - } - - static int real_clear_call_capable(std::false_type, lua_State* L) { - static const std::string& s = detail::demangle(); - return luaL_error(L, "sol: cannot call clear on type %s", s.c_str()); - } - - static int real_clear_call_capable(std::true_type, lua_State* L) { - auto& src = get_src(L); - src.clear(); - return 0; - } - - static int real_clear_call(lua_State*L) { - return real_clear_call_capable(std::integral_constant::value>(), L); - } - - static int add_call(lua_State*L) { - return detail::static_trampoline<(&real_add_call)>(L); - } - - static int insert_call(lua_State*L) { - return detail::static_trampoline<(&real_insert_call)>(L); - } - - static int clear_call(lua_State*L) { - return detail::static_trampoline<(&real_clear_call)>(L); - } - - static int length_call(lua_State*L) { - return detail::static_trampoline<(&real_length_call)>(L); - } - - static int pairs_next_call(lua_State*L) { - return detail::static_trampoline<(&real_pairs_next_call)>(L); - } - - static int pairs_call(lua_State*L) { - return detail::static_trampoline<(&real_pairs_call)>(L); - } - - static int index_call(lua_State*L) { - return detail::static_trampoline<(&real_index_call)>(L); - } - - static int new_index_call(lua_State*L) { - return detail::static_trampoline<(&real_new_index_call)>(L); - } - }; - - namespace stack { - namespace stack_detail { - template - inline auto container_metatable() { - typedef container_usertype_metatable> meta_cumt; - std::array reg = { { - { "__index", &meta_cumt::index_call }, - { "__newindex", &meta_cumt::new_index_call }, - { "__pairs", &meta_cumt::pairs_call }, - { "__ipairs", &meta_cumt::pairs_call }, - { "__len", &meta_cumt::length_call }, - { "clear", &meta_cumt::clear_call }, - { "insert", &meta_cumt::insert_call }, - { "add", &meta_cumt::add_call }, - std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy }, - { nullptr, nullptr } - } }; - return reg; - } - - template - inline auto container_metatable_behind() { - typedef container_usertype_metatable> meta_cumt; - std::array reg = { { - { "__index", &meta_cumt::index_call }, - { "__newindex", &meta_cumt::new_index_call }, - { nullptr, nullptr } - } }; - return reg; - } - - template - struct metatable_setup { - lua_State* L; - - metatable_setup(lua_State* L) : L(L) {} - - void operator()() { - static const auto reg = container_metatable(); - static const auto containerreg = container_metatable_behind(); - static const char* metakey = &usertype_traits::metatable()[0]; - - if (luaL_newmetatable(L, metakey) == 1) { - stack_reference metatable(L, -1); - luaL_setfuncs(L, reg.data(), 0); - - lua_createtable(L, 0, static_cast(containerreg.size())); - stack_reference metabehind(L, -1); - luaL_setfuncs(L, containerreg.data(), 0); - - stack::set_field(L, metatable_key, metabehind, metatable.stack_index()); - metabehind.pop(); - } - lua_setmetatable(L, -2); - } - }; - } - - template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { - static int push(lua_State* L, const T& cont) { - stack_detail::metatable_setup fx(L); - return pusher>{}.push_fx(L, fx, cont); - } - - static int push(lua_State* L, T&& cont) { - stack_detail::metatable_setup fx(L); - return pusher>{}.push_fx(L, fx, std::move(cont)); - } - }; - - template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { - static int push(lua_State* L, T* cont) { - stack_detail::metatable_setup>*> fx(L); - return pusher>{}.push_fx(L, fx, cont); - } - }; - } // stack - -} // sol - -// end of sol/container_usertype_metatable.hpp - -namespace sol { - - template - class usertype { - private: - std::unique_ptr metatableregister; - - template - usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter, Args...>, detail::deleter>(std::forward(args)...)) {} - - template - usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward(args)..., "__gc", default_destructor) {} - - template - usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} - - public: - - template - usertype(Args&&... args) : usertype(meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(args)...) {} - - template - usertype(constructors constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} - - template - usertype(constructor_wrapper constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} - - template - usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter, detail::deleter>(L, std::forward(args)...)) {} - - usertype_detail::registrar* registrar_data() { - return metatableregister.get(); - } - - int push(lua_State* L) { - int r = metatableregister->push_um(L); - metatableregister = nullptr; - return r; - } - }; - - template - class simple_usertype : public usertype { - private: - typedef usertype base_t; - lua_State* state; - - public: - template - simple_usertype(lua_State* L, Args&&... args) : base_t(simple, L, std::forward(args)...), state(L) {} - - template - void set(N&& n, F&& f) { - auto meta = static_cast*>(base_t::registrar_data()); - meta->add(state, n, f); - } - }; - - namespace stack { - template - struct pusher> { - static int push(lua_State* L, usertype& user) { - return user.push(L); - } - }; - } // stack -} // sol - -// end of sol/usertype.hpp - -// beginning of sol/table_iterator.hpp - -namespace sol { - - template - class basic_table_iterator : public std::iterator> { - private: - typedef std::iterator> base_t; - public: - typedef object key_type; - typedef object mapped_type; - typedef base_t::value_type value_type; - typedef base_t::iterator_category iterator_category; - typedef base_t::difference_type difference_type; - typedef base_t::pointer pointer; - typedef base_t::reference reference; - typedef const value_type& const_reference; - - private: - std::pair kvp; - reference_type ref; - int tableidx = 0; - int keyidx = 0; - std::ptrdiff_t idx = 0; - - public: - - basic_table_iterator() : keyidx(-1), idx(-1) { - - } - - basic_table_iterator(reference_type x) : ref(std::move(x)) { - ref.push(); - tableidx = lua_gettop(ref.lua_state()); - stack::push(ref.lua_state(), lua_nil); - this->operator++(); - if (idx == -1) { - return; - } - --idx; - } - - basic_table_iterator& operator++() { - if (idx == -1) - return *this; - - if (lua_next(ref.lua_state(), tableidx) == 0) { - idx = -1; - keyidx = -1; - return *this; - } - ++idx; - kvp.first = object(ref.lua_state(), -2); - kvp.second = object(ref.lua_state(), -1); - lua_pop(ref.lua_state(), 1); - // leave key on the stack - keyidx = lua_gettop(ref.lua_state()); - return *this; - } - - basic_table_iterator operator++(int) { - auto saved = *this; - this->operator++(); - return saved; - } - - reference operator*() { - return kvp; - } - - const_reference operator*() const { - return kvp; - } - - bool operator== (const basic_table_iterator& right) const { - return idx == right.idx; - } - - bool operator!= (const basic_table_iterator& right) const { - return idx != right.idx; - } - - ~basic_table_iterator() { - if (keyidx != -1) { - stack::remove(ref.lua_state(), keyidx, 1); - } - if (ref.valid()) { - stack::remove(ref.lua_state(), tableidx, 1); - } - } - }; - -} // sol - -// end of sol/table_iterator.hpp - -namespace sol { - namespace detail { - template - struct clean { lua_State* L; clean(lua_State* luastate) : L(luastate) {} ~clean() { lua_pop(L, static_cast(n)); } }; - struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* luastate, int& n) : L(luastate), n(n) {} ~ref_clean() { lua_pop(L, static_cast(n)); } }; - inline int fail_on_newindex(lua_State* L) { - return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); - } - } - - const new_table create = new_table{}; - - template - class basic_table_core : public basic_object_base { - typedef basic_object_base base_t; - friend class state; - friend class state_view; - - template - using is_global = meta::all, meta::is_c_str...>; - - template - void for_each(std::true_type, Fx&& fx) const { - auto pp = stack::push_pop(*this); - stack::push(base_t::lua_state(), lua_nil); - while (lua_next(base_t::lua_state(), -2)) { - sol::object key(base_t::lua_state(), -2); - sol::object value(base_t::lua_state(), -1); - std::pair keyvalue(key, value); - auto pn = stack::pop_n(base_t::lua_state(), 1); - fx(keyvalue); - } - } - - template - void for_each(std::false_type, Fx&& fx) const { - auto pp = stack::push_pop(*this); - stack::push(base_t::lua_state(), lua_nil); - while (lua_next(base_t::lua_state(), -2)) { - sol::object key(base_t::lua_state(), -2); - sol::object value(base_t::lua_state(), -1); - auto pn = stack::pop_n(base_t::lua_state(), 1); - fx(key, value); - } - } - - template - auto tuple_get(types, std::index_sequence<0, 1, I...>, Keys&& keys) const - -> decltype(stack::pop>(nullptr)) { - typedef decltype(stack::pop>(nullptr)) Tup; - return Tup( - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<0>(keys)), - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<1>(keys)), - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys))... - ); - } - - template - decltype(auto) tuple_get(types, std::index_sequence, Keys&& keys) const { - return traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys)); - } - - template - void tuple_set(std::index_sequence, Pairs&& pairs) { - auto pp = stack::push_pop(pairs))...>::value)>(*this); - void(detail::swallow{ (stack::set_field(base_t::lua_state(), - detail::forward_get(pairs), - detail::forward_get(pairs), - lua_gettop(base_t::lua_state()) - ), 0)... }); - } - - template - decltype(auto) traverse_get_deep(Key&& key) const { - stack::get_field(base_t::lua_state(), std::forward(key)); - return stack::get(base_t::lua_state()); - } - - template - decltype(auto) traverse_get_deep(Key&& key, Keys&&... keys) const { - stack::get_field(base_t::lua_state(), std::forward(key)); - return traverse_get_deep(std::forward(keys)...); - } - - template - decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key) const { - typedef decltype(stack::get(base_t::lua_state())) R; - auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), lua_gettop(base_t::lua_state())); - popcount += p.levels; - if (!p.success) - return R(nullopt); - return stack::get(base_t::lua_state()); - } - - template - decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key, Keys&&... keys) const { - auto p = I > 0 ? stack::probe_get_field(base_t::lua_state(), std::forward(key), -1) : stack::probe_get_field(base_t::lua_state(), std::forward(key), lua_gettop(base_t::lua_state())); - popcount += p.levels; - if (!p.success) - return T(nullopt); - return traverse_get_deep_optional(popcount, std::forward(keys)...); - } - - template - decltype(auto) traverse_get_optional(std::false_type, Keys&&... keys) const { - detail::clean c(base_t::lua_state()); - return traverse_get_deep(std::forward(keys)...); - } - - template - decltype(auto) traverse_get_optional(std::true_type, Keys&&... keys) const { - int popcount = 0; - detail::ref_clean c(base_t::lua_state(), popcount); - return traverse_get_deep_optional(popcount, std::forward(keys)...); - } - - template - void traverse_set_deep(Key&& key, Value&& value) const { - stack::set_field(base_t::lua_state(), std::forward(key), std::forward(value)); - } - - template - void traverse_set_deep(Key&& key, Keys&&... keys) const { - stack::get_field(base_t::lua_state(), std::forward(key)); - traverse_set_deep(std::forward(keys)...); - } - - basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { } - - protected: - basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {} - basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {} - template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) {} - - public: - typedef basic_table_iterator iterator; - typedef iterator const_iterator; - - basic_table_core() noexcept = default; - basic_table_core(const basic_table_core&) = default; - basic_table_core(basic_table_core&&) = default; - basic_table_core& operator=(const basic_table_core&) = default; - basic_table_core& operator=(basic_table_core&&) = default; - basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {} - basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {} - template >>, meta::neg, ref_index>>> = meta::enabler> - basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {} - basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { - if (!std::is_base_of::value) { - lua_pop(L, 1); - } - } - basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(L, index, type_panic); -#endif // Safety - } - basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - stack::check(L, -1, type_panic); -#endif // Safety - } - template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_table>::value) { - auto pp = stack::push_pop(*this); - stack::check(base_t::lua_state(), -1, type_panic); - } -#endif // Safety - } - - iterator begin() const { - return iterator(*this); - } - - iterator end() const { - return iterator(); - } - - const_iterator cbegin() const { - return begin(); - } - - const_iterator cend() const { - return end(); - } - - template - decltype(auto) get(Keys&&... keys) const { - static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); - auto pp = stack::push_pop::value>(*this); - return tuple_get(types(), std::make_index_sequence(), std::forward_as_tuple(std::forward(keys)...)); - } - - template - decltype(auto) get_or(Key&& key, T&& otherwise) const { - typedef decltype(get("")) U; - sol::optional option = get>(std::forward(key)); - if (option) { - return static_cast(option.value()); - } - return static_cast(std::forward(otherwise)); - } - - template - decltype(auto) get_or(Key&& key, D&& otherwise) const { - sol::optional option = get>(std::forward(key)); - if (option) { - return static_cast(option.value()); - } - return static_cast(std::forward(otherwise)); - } - - template - decltype(auto) traverse_get(Keys&&... keys) const { - auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_specialization_of>(), std::forward(keys)...); - } - - template - basic_table_core& traverse_set(Keys&&... keys) { - auto pp = stack::push_pop::value>(*this); - auto pn = stack::pop_n(base_t::lua_state(), static_cast(sizeof...(Keys)-2)); - traverse_set_deep(std::forward(keys)...); - return *this; - } - - template - basic_table_core& set(Args&&... args) { - tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); - return *this; - } - - template - basic_table_core& set_usertype(usertype& user) { - return set_usertype(usertype_traits::name(), user); - } - - template - basic_table_core& set_usertype(Key&& key, usertype& user) { - return set(std::forward(key), user); - } - - template - basic_table_core& new_usertype(const std::string& name, Args&&... args) { - usertype utype(std::forward(args)...); - set_usertype(name, utype); - return *this; - } - - template - basic_table_core& new_usertype(const std::string& name, Args&&... args) { - constructors> ctor{}; - return new_usertype(name, ctor, std::forward(args)...); - } - - template - basic_table_core& new_usertype(const std::string& name, constructors ctor, Args&&... args) { - usertype utype(ctor, std::forward(args)...); - set_usertype(name, utype); - return *this; - } - - template - basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { - simple_usertype utype(base_t::lua_state(), std::forward(args)...); - set_usertype(name, utype); - return *this; - } - - template - basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { - constructors> ctor{}; - return new_simple_usertype(name, ctor, std::forward(args)...); - } - - template - basic_table_core& new_simple_usertype(const std::string& name, constructors ctor, Args&&... args) { - simple_usertype utype(base_t::lua_state(), ctor, std::forward(args)...); - set_usertype(name, utype); - return *this; - } - - template - simple_usertype create_simple_usertype(Args&&... args) { - simple_usertype utype(base_t::lua_state(), std::forward(args)...); - return utype; - } - - template - simple_usertype create_simple_usertype(Args&&... args) { - constructors> ctor{}; - return create_simple_usertype(ctor, std::forward(args)...); - } - - template - simple_usertype create_simple_usertype(constructors ctor, Args&&... args) { - simple_usertype utype(base_t::lua_state(), ctor, std::forward(args)...); - return utype; - } - - template - basic_table_core& new_enum(const std::string& name, Args&&... args) { - if (read_only) { - table idx = create_with(std::forward(args)...); - table x = create_with( - meta_function::new_index, detail::fail_on_newindex, - meta_function::index, idx - ); - table target = create_named(name); - target[metatable_key] = x; - } - else { - create_named(name, std::forward(args)...); - } - return *this; - } - - template - void for_each(Fx&& fx) const { - typedef meta::is_invokable)> is_paired; - for_each(is_paired(), std::forward(fx)); - } - - size_t size() const { - auto pp = stack::push_pop(*this); - lua_len(base_t::lua_state(), -1); - return stack::pop(base_t::lua_state()); - } - - bool empty() const { - return cbegin() == cend(); - } - - template - proxy operator[](T&& key) & { - return proxy(*this, std::forward(key)); - } - - template - proxy operator[](T&& key) const & { - return proxy(*this, std::forward(key)); - } - - template - proxy operator[](T&& key) && { - return proxy(*this, std::forward(key)); - } - - template - basic_table_core& set_function(Key&& key, Args&&... args) { - set_fx(types(), std::forward(key), std::forward(args)...); - return *this; - } - - template - basic_table_core& set_function(Key&& key, Args&&... args) { - set_fx(types<>(), std::forward(key), std::forward(args)...); - return *this; - } - - template - basic_table_core& add(Args&&... args) { - auto pp = stack::push_pop(*this); - (void)detail::swallow{0, - (stack::set_ref(base_t::lua_state(), std::forward(args)), 0)... - }; - return *this; - } - - private: - template> - void set_fx(types, Key&& key, Fx&& fx) { - set_resolved_function(std::forward(key), std::forward(fx)); - } - - template>> = meta::enabler> - void set_fx(types<>, Key&& key, Fx&& fx) { - set(std::forward(key), std::forward(fx)); - } - - template>> = meta::enabler> - void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { - set(std::forward(key), as_function_reference(std::forward(fx), std::forward(args)...)); - } - - template - void set_resolved_function(Key&& key, Args&&... args) { - set(std::forward(key), as_function_reference>(std::forward(args)...)); - } - - public: - static inline table create(lua_State* L, int narr = 0, int nrec = 0) { - lua_createtable(L, narr, nrec); - table result(L); - lua_pop(L, 1); - return result; - } - - template - static inline table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - lua_createtable(L, narr, nrec); - table result(L); - result.set(std::forward(key), std::forward(value), std::forward(args)...); - lua_pop(L, 1); - return result; - } - - template - static inline table create_with(lua_State* L, Args&&... args) { - static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list."); - static const int narr = static_cast(meta::count_2_for_pack::value); - return create(L, narr, static_cast((sizeof...(Args) / 2) - narr), std::forward(args)...); - } - - table create(int narr = 0, int nrec = 0) { - return create(base_t::lua_state(), narr, nrec); - } - - template - table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - return create(base_t::lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); - } - - template - table create(Name&& name, int narr = 0, int nrec = 0) { - table x = create(base_t::lua_state(), narr, nrec); - this->set(std::forward(name), x); - return x; - } - - template - table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - table x = create(base_t::lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); - this->set(std::forward(name), x); - return x; - } - - template - table create_with(Args&&... args) { - return create_with(base_t::lua_state(), std::forward(args)...); - } - - template - table create_named(Name&& name, Args&&... args) { - static const int narr = static_cast(meta::count_2_for_pack::value); - return create(std::forward(name), narr, sizeof...(Args) / 2 - narr, std::forward(args)...); - } - - ~basic_table_core() { - - } - }; -} // sol - -// end of sol/table_core.hpp - -namespace sol { - typedef table_core table; - - namespace stack { - template <> - struct getter { - static table get(lua_State* L, int index = -1) { - if (lua_getmetatable(L, index) == 0) { - return table(L, ref_index(LUA_REFNIL)); - } - return table(L, -1); - } - }; - } // stack -} // sol - -// end of sol/table.hpp - -// beginning of sol/environment.hpp - -namespace sol { - - template - struct basic_environment : basic_table { - private: - typedef basic_table base_t; - - public: - basic_environment() noexcept = default; - basic_environment(const basic_environment&) = default; - basic_environment(basic_environment&&) = default; - basic_environment& operator=(const basic_environment&) = default; - basic_environment& operator=(basic_environment&&) = default; - basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {} - basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {} - - basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {} - basic_environment(lua_State* L, new_table t, const reference& fallback) : basic_environment(L, std::move(t)) { - sol::stack_table mt(L, sol::new_table(0, 1)); - mt.set(sol::meta_function::index, fallback); - this->set(metatable_key, mt); - mt.pop(); - } - - basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(this->lua_state(), -1, type_panic); -#endif // Safety - lua_pop(this->lua_state(), 2); - } - basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(this->lua_state(), -1, type_panic); -#endif // Safety - lua_pop(this->lua_state(), 2); - } - basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(L, index, type_panic); -#endif // Safety - } - basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - stack::check(L, -1, type_panic); -#endif // Safety - } - template , basic_environment>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_environment>::value) { - auto pp = stack::push_pop(*this); - stack::check(base_t::lua_state(), -1, type_panic); - } -#endif // Safety - } - - template - void set_on(const T& target) const { - lua_State* L = target.lua_state(); - auto pp = stack::push_pop(target); -#if SOL_LUA_VERSION < 502 - // Use lua_setfenv - this->push(); - lua_setfenv(L, -2); -#else - // Use upvalues as explained in Lua 5.2 and beyond's manual - this->push(); - if (lua_setupvalue(L, -2, 1) == nullptr) { - this->pop(); - } -#endif - } - }; - - template - void set_environment(const basic_environment& env, const T& target) { - env.set_on(target); - } - - template - basic_environment get_environment(const T& target) { - lua_State* L = target.lua_state(); - auto pp = stack::pop_n(L, stack::push_environment_of(target)); - return basic_environment(L, -1); - } - - namespace stack { - template <> - struct getter { - static environment get(lua_State* L, int index = -1) { - return get_environment(stack_reference(L, raw_index(index))); - } - }; - } // stack -} // sol - -// end of sol/environment.hpp - -// beginning of sol/load_result.hpp - -namespace sol { - struct load_result : public proxy_base { - private: - lua_State* L; - int index; - int returncount; - int popcount; - load_status err; - - template - decltype(auto) tagged_get(types>) const { - if (!valid()) { - return sol::optional(nullopt); - } - return stack::get>(L, index); - } - - template - decltype(auto) tagged_get(types) const { -#ifdef SOL_CHECK_ARGUMENTS - if (!valid()) { - type_panic(L, index, type_of(L, index), type::none); - } -#endif // Check Argument Safety - return stack::get(L, index); - } - - sol::optional tagged_get(types>) const { - if (valid()) { - return nullopt; - } - return sol::error(detail::direct_error, stack::get(L, index)); - } - - sol::error tagged_get(types) const { -#ifdef SOL_CHECK_ARGUMENTS - if (valid()) { - type_panic(L, index, type_of(L, index), type::none); - } -#endif // Check Argument Safety - return sol::error(detail::direct_error, stack::get(L, index)); - } - - public: - load_result() = default; - load_result(lua_State* Ls, int stackindex = -1, int retnum = 0, int popnum = 0, load_status lerr = load_status::ok) noexcept : L(Ls), index(stackindex), returncount(retnum), popcount(popnum), err(lerr) { - - } - load_result(const load_result&) = default; - load_result& operator=(const load_result&) = default; - load_result(load_result&& o) noexcept : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but we will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = load_status::syntax; - } - load_result& operator=(load_result&& o) noexcept { - L = o.L; - index = o.index; - returncount = o.returncount; - popcount = o.popcount; - err = o.err; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but we will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = load_status::syntax; - return *this; - } - - load_status status() const noexcept { - return err; - } - - bool valid() const noexcept { - return status() == load_status::ok; - } - - template - T get() const { - return tagged_get(types>()); - } - - template - decltype(auto) call(Args&&... args) { - return get().template call(std::forward(args)...); - } - - template - decltype(auto) operator()(Args&&... args) { - return call<>(std::forward(args)...); - } - - lua_State* lua_state() const noexcept { return L; }; - int stack_index() const noexcept { return index; }; - - ~load_result() { - stack::remove(L, index, popcount); - } - }; -} // sol - -// end of sol/load_result.hpp - -namespace sol { - enum class lib : char { - base, - package, - coroutine, - string, - os, - math, - table, - debug, - bit32, - io, - ffi, - jit, - utf8, - count - }; - - inline std::size_t total_memory_used(lua_State* L) { - std::size_t kb = lua_gc(L, LUA_GCCOUNT, 0); - kb *= 1024; - kb += lua_gc(L, LUA_GCCOUNTB, 0); - return kb; - } - - inline protected_function_result simple_on_error(lua_State*, sol::protected_function_result result) { - return result; - } - - inline protected_function_result default_on_error( lua_State* L, protected_function_result pfr ) { - type t = type_of(L, pfr.stack_index()); - std::string err = to_string(pfr.status()) + " error"; - if (t == type::string) { - err += " "; - err += stack::get(L, pfr.stack_index()); - } -#ifdef SOL_NO_EXCEPTIONS - if (t != type::nil) { - lua_pop(L, 1); - } - stack::push(L, err); - lua_error(L); -#else - throw error(detail::direct_error, err); -#endif - return pfr; - } - - class state_view { - private: - lua_State* L; - table reg; - global_table global; - - optional is_loaded_package(const std::string& key) { - auto loaded = reg.traverse_get>("_LOADED", key); - bool is53mod = loaded && !(loaded->is() && !loaded->as()); - if (is53mod) - return loaded; -#if SOL_LUA_VERSION <= 501 - auto loaded51 = global.traverse_get>("package", "loaded", key); - bool is51mod = loaded51 && !(loaded51->is() && !loaded51->as()); - if (is51mod) - return loaded51; -#endif - return nullopt; - } - - template - void ensure_package(const std::string& key, T&& sr) { -#if SOL_LUA_VERSION <= 501 - auto pkg = global["package"]; - if (!pkg.valid()) { - pkg = create_table_with("loaded", create_table_with(key, sr)); - } - else { - auto ld = pkg["loaded"]; - if (!ld.valid()) { - ld = create_table_with(key, sr); - } - else { - ld[key] = sr; - } - } -#endif - auto loaded = reg["_LOADED"]; - if (!loaded.valid()) { - loaded = create_table_with(key, sr); - } - else { - loaded[key] = sr; - } - } - - template - object require_core(const std::string& key, Fx&& action, bool create_global = true) { - optional loaded = is_loaded_package(key); - if (loaded && loaded->valid()) - return std::move(*loaded); - action(); - auto sr = stack::get(L); - if (create_global) - set(key, sr); - ensure_package(key, sr); - return stack::pop(L); - } - - public: - typedef global_table::iterator iterator; - typedef global_table::const_iterator const_iterator; - - state_view(lua_State* Ls) : - L(Ls), - reg(Ls, LUA_REGISTRYINDEX), - global(Ls, detail::global_) { - - } - - state_view(this_state Ls) : state_view(Ls.L){ - - } - - lua_State* lua_state() const { - return L; - } - - template - void open_libraries(Args&&... args) { - static_assert(meta::all_same::value, "all types must be libraries"); - if (sizeof...(args) == 0) { - luaL_openlibs(L); - return; - } - - lib libraries[1 + sizeof...(args)] = { lib::count, std::forward(args)... }; - - for (auto&& library : libraries) { - switch (library) { -#if SOL_LUA_VERSION <= 501 && defined(SOL_LUAJIT) - case lib::coroutine: -#endif // luajit opens coroutine base stuff - case lib::base: - luaL_requiref(L, "base", luaopen_base, 1); - lua_pop(L, 1); - break; - case lib::package: - luaL_requiref(L, "package", luaopen_package, 1); - lua_pop(L, 1); - break; -#if !defined(SOL_LUAJIT) - case lib::coroutine: -#if SOL_LUA_VERSION > 501 - luaL_requiref(L, "coroutine", luaopen_coroutine, 1); - lua_pop(L, 1); -#endif // Lua 5.2+ only - break; -#endif // Not LuaJIT - comes builtin - case lib::string: - luaL_requiref(L, "string", luaopen_string, 1); - lua_pop(L, 1); - break; - case lib::table: - luaL_requiref(L, "table", luaopen_table, 1); - lua_pop(L, 1); - break; - case lib::math: - luaL_requiref(L, "math", luaopen_math, 1); - lua_pop(L, 1); - break; - case lib::bit32: -#ifdef SOL_LUAJIT - luaL_requiref(L, "bit32", luaopen_bit, 1); - lua_pop(L, 1); -#elif (SOL_LUA_VERSION == 502) || defined(LUA_COMPAT_BITLIB) || defined(LUA_COMPAT_5_2) - luaL_requiref(L, "bit32", luaopen_bit32, 1); - lua_pop(L, 1); -#else -#endif // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags) - break; - case lib::io: - luaL_requiref(L, "io", luaopen_io, 1); - lua_pop(L, 1); - break; - case lib::os: - luaL_requiref(L, "os", luaopen_os, 1); - lua_pop(L, 1); - break; - case lib::debug: - luaL_requiref(L, "debug", luaopen_debug, 1); - lua_pop(L, 1); - break; - case lib::utf8: -#if SOL_LUA_VERSION > 502 && !defined(SOL_LUAJIT) - luaL_requiref(L, "utf8", luaopen_utf8, 1); - lua_pop(L, 1); -#endif // Lua 5.3+ only - break; - case lib::ffi: -#ifdef SOL_LUAJIT - luaL_requiref(L, "ffi", luaopen_ffi, 1); - lua_pop(L, 1); -#endif // LuaJIT only - break; - case lib::jit: -#ifdef SOL_LUAJIT - luaL_requiref(L, "jit", luaopen_jit, 1); - lua_pop(L, 1); -#endif // LuaJIT Only - break; - case lib::count: - default: - break; - } - } - } - - object require(const std::string& key, lua_CFunction open_function, bool create_global = true) { - luaL_requiref(L, key.c_str(), open_function, create_global ? 1 : 0); - return stack::pop(L); - } - - object require_script(const std::string& key, const std::string& code, bool create_global = true) { - return require_core(key, [this, &code]() {stack::script(L, code); }, create_global); - } - - object require_file(const std::string& key, const std::string& filename, bool create_global = true) { - return require_core(key, [this, &filename]() {stack::script_file(L, filename); }, create_global); - } - - template - protected_function_result do_string(const std::string& code, const basic_environment& env) { - load_status x = static_cast(luaL_loadstring(L, code.c_str())); - if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); - } - protected_function pf(L, -1); - pf.pop(); - set_environment(env, pf); - return pf(); - } - - template - protected_function_result do_file(const std::string& filename, const basic_environment& env) { - load_status x = static_cast(luaL_loadfile(L, filename.c_str())); - if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); - } - protected_function pf(L, -1); - pf.pop(); - set_environment(env, pf); - return pf(); - } - - protected_function_result do_string(const std::string& code) { - load_status x = static_cast(luaL_loadstring(L, code.c_str())); - if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); - } - protected_function pf(L, -1); - pf.pop(); - return pf(); - } - - protected_function_result do_file(const std::string& filename) { - load_status x = static_cast(luaL_loadfile(L, filename.c_str())); - if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); - } - protected_function pf(L, -1); - pf.pop(); - return pf(); - } - - protected_function_result script(const std::string& code, const environment& env) { - return script(code, env, sol::default_on_error); - } - - protected_function_result script_file(const std::string& filename, const environment& env) { - return script_file(filename, env, sol::default_on_error); - } - - template >> = meta::enabler> - protected_function_result script(const std::string& code, Fx&& on_error) { - protected_function_result pfr = do_string(code); - if (!pfr.valid()) { - return on_error(L, std::move(pfr)); - } - return pfr; - } - - template >> = meta::enabler> - protected_function_result script_file(const std::string& filename, Fx&& on_error) { - protected_function_result pfr = do_file(filename); - if (!pfr.valid()) { - return on_error(L, std::move(pfr)); - } - return pfr; - } - - template - protected_function_result script(const std::string& code, const basic_environment& env, Fx&& on_error) { - protected_function_result pfr = do_string(code, env); - if (!pfr.valid()) { - return on_error(L, std::move(pfr)); - } - return pfr; - } - - template - protected_function_result script_file(const std::string& filename, const basic_environment& env, Fx&& on_error) { - protected_function_result pfr = do_file(filename, env); - if (!pfr.valid()) { - return on_error(L, std::move(pfr)); - } - return pfr; - } - - function_result script(const std::string& code) { - int index = lua_gettop(L); - stack::script(L, code); - int postindex = lua_gettop(L); - int returns = postindex - index; - return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); - } - - function_result script_file(const std::string& filename) { - int index = lua_gettop(L); - stack::script_file(L, filename); - int postindex = lua_gettop(L); - int returns = postindex - index; - return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); - } - - load_result load(const std::string& code) { - load_status x = static_cast(luaL_loadstring(L, code.c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); - } - - load_result load_file(const std::string& filename) { - load_status x = static_cast(luaL_loadfile(L, filename.c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); - } - - load_result load_buffer(const char *buff, size_t size, const char *name, const char* mode = nullptr) { - load_status x = static_cast(luaL_loadbufferx(L, buff, size, name, mode)); - return load_result(L, lua_absindex(L, -1), 1, 1, x); - } - - iterator begin() const { - return global.begin(); - } - - iterator end() const { - return global.end(); - } - - const_iterator cbegin() const { - return global.cbegin(); - } - - const_iterator cend() const { - return global.cend(); - } - - global_table globals() const { - return global; - } - - table registry() const { - return reg; - } - - std::size_t memory_used() const { - return total_memory_used(lua_state()); - } - - void collect_garbage() { - lua_gc(lua_state(), LUA_GCCOLLECT, 0); - } - - operator lua_State* () const { - return lua_state(); - } - - void set_panic(lua_CFunction panic) { - lua_atpanic(L, panic); - } - - template - decltype(auto) get(Keys&&... keys) const { - return global.get(std::forward(keys)...); - } - - template - decltype(auto) get_or(Key&& key, T&& otherwise) const { - return global.get_or(std::forward(key), std::forward(otherwise)); - } - - template - decltype(auto) get_or(Key&& key, D&& otherwise) const { - return global.get_or(std::forward(key), std::forward(otherwise)); - } - - template - state_view& set(Args&&... args) { - global.set(std::forward(args)...); - return *this; - } - - template - decltype(auto) traverse_get(Keys&&... keys) const { - return global.traverse_get(std::forward(keys)...); - } - - template - state_view& traverse_set(Args&&... args) { - global.traverse_set(std::forward(args)...); - return *this; - } - - template - state_view& set_usertype(usertype& user) { - return set_usertype(usertype_traits::name(), user); - } - - template - state_view& set_usertype(Key&& key, usertype& user) { - global.set_usertype(std::forward(key), user); - return *this; - } - - template - state_view& new_usertype(const std::string& name, Args&&... args) { - global.new_usertype(name, std::forward(args)...); - return *this; - } - - template - state_view& new_usertype(const std::string& name, Args&&... args) { - global.new_usertype(name, std::forward(args)...); - return *this; - } - - template - state_view& new_usertype(const std::string& name, constructors ctor, Args&&... args) { - global.new_usertype(name, ctor, std::forward(args)...); - return *this; - } - - template - state_view& new_simple_usertype(const std::string& name, Args&&... args) { - global.new_simple_usertype(name, std::forward(args)...); - return *this; - } - - template - state_view& new_simple_usertype(const std::string& name, Args&&... args) { - global.new_simple_usertype(name, std::forward(args)...); - return *this; - } - - template - state_view& new_simple_usertype(const std::string& name, constructors ctor, Args&&... args) { - global.new_simple_usertype(name, ctor, std::forward(args)...); - return *this; - } - - template - simple_usertype create_simple_usertype(Args&&... args) { - return global.create_simple_usertype(std::forward(args)...); - } - - template - simple_usertype create_simple_usertype(Args&&... args) { - return global.create_simple_usertype(std::forward(args)...); - } - - template - simple_usertype create_simple_usertype(constructors ctor, Args&&... args) { - return global.create_simple_usertype(ctor, std::forward(args)...); - } - - template - state_view& new_enum(const std::string& name, Args&&... args) { - global.new_enum(name, std::forward(args)...); - return *this; - } - - template - void for_each(Fx&& fx) { - global.for_each(std::forward(fx)); - } - - template - proxy operator[](T&& key) { - return global[std::forward(key)]; - } - - template - proxy operator[](T&& key) const { - return global[std::forward(key)]; - } - - template - state_view& set_function(Key&& key, Args&&... args) { - global.set_function(std::forward(key), std::forward(args)...); - return *this; - } - - template - state_view& set_function(Key&& key, Args&&... args) { - global.set_function(std::forward(key), std::forward(args)...); - return *this; - } - - template - table create_table(Name&& name, int narr = 0, int nrec = 0) { - return global.create(std::forward(name), narr, nrec); - } - - template - table create_table(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - return global.create(std::forward(name), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); - } - - template - table create_named_table(Name&& name, Args&&... args) { - table x = global.create_with(std::forward(args)...); - global.set(std::forward(name), x); - return x; - } - - table create_table(int narr = 0, int nrec = 0) { - return create_table(lua_state(), narr, nrec); - } - - template - table create_table(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - return create_table(lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); - } - - template - table create_table_with(Args&&... args) { - return create_table_with(lua_state(), std::forward(args)...); - } - - static inline table create_table(lua_State* L, int narr = 0, int nrec = 0) { - return global_table::create(L, narr, nrec); - } - - template - static inline table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - return global_table::create(L, narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); - } - - template - static inline table create_table_with(lua_State* L, Args&&... args) { - return global_table::create_with(L, std::forward(args)...); - } - }; -} // sol - -// end of sol/state_view.hpp - -namespace sol { - inline int default_at_panic(lua_State* L) { -#ifdef SOL_NO_EXCEPTIONS - (void)L; - return -1; -#else - const char* message = lua_tostring(L, -1); - if (message) { - std::string err = message; - lua_settop(L, 0); - throw error(err); - } - lua_settop(L, 0); - throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic")); -#endif - } - - inline int default_error_handler(lua_State*L) { - using namespace sol; - std::string msg = "An unknown error has triggered the default error handler"; - optional maybetopmsg = stack::check_get(L, 1); - if (maybetopmsg) { - const string_detail::string_shim& topmsg = maybetopmsg.value(); - msg.assign(topmsg.c_str(), topmsg.size()); - } - luaL_traceback(L, L, msg.c_str(), 1); - optional maybetraceback = stack::check_get(L, -1); - if (maybetraceback) { - const string_detail::string_shim& traceback = maybetraceback.value(); - msg.assign(traceback.c_str(), traceback.size()); - } - return stack::push(L, msg); - } - - class state : private std::unique_ptr, public state_view { - private: - typedef std::unique_ptr unique_base; - public: - state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close), - state_view(unique_base::get()) { - set_panic(panic); - stack::luajit_exception_handler(unique_base::get()); - } - - state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close), - state_view(unique_base::get()) { - set_panic(panic); - sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler)); - stack::luajit_exception_handler(unique_base::get()); - } - - state(const state&) = delete; - state(state&&) = default; - state& operator=(const state&) = delete; - state& operator=(state&& that) { - state_view::operator=(std::move(that)); - unique_base::operator=(std::move(that)); - return *this; - } - - using state_view::get; - - ~state() { - auto& handler = protected_function::get_default_handler(); - if (handler.lua_state() == this->lua_state()) { - protected_function::set_default_handler(reference()); - } - } - }; -} // sol - -// end of sol/state.hpp - -// beginning of sol/coroutine.hpp - -// beginning of sol/thread.hpp - -namespace sol { - struct lua_thread_state { - lua_State* L; - operator lua_State* () const { - return L; - } - lua_State* operator-> () const { - return L; - } - }; - - namespace stack { - - template <> - struct pusher { - int push(lua_State*, lua_thread_state lts) { - lua_pushthread(lts.L); - return 1; - } - }; - - template <> - struct getter { - lua_thread_state get(lua_State* L, int index, record& tracking) { - tracking.use(1); - lua_thread_state lts{ lua_tothread(L, index) }; - return lts; - } - }; - - template <> - struct check_getter { - template - optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - lua_thread_state lts{ lua_tothread(L, index) }; - if (lts.L == nullptr) { - handler(L, index, type::thread, type_of(L, index)); - return nullopt; - } - tracking.use(1); - return lts; - } - }; - - } - -#if SOL_LUA_VERSION < 502 - inline lua_State* main_thread(lua_State*, lua_State* backup_if_unsupported = nullptr) { - return backup_if_unsupported; - } -#else - inline lua_State* main_thread(lua_State* L, lua_State* = nullptr) { - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); - lua_thread_state s = stack::pop(L); - return s.L; - } -#endif // Lua 5.2+ has the main thread getter - - class thread : public reference { - public: - thread() noexcept = default; - thread(const thread&) = default; - thread(thread&&) = default; - template , thread>>, std::is_base_of>> = meta::enabler> - thread(T&& r) : reference(std::forward(r)) {} - thread(const stack_reference& r) : thread(r.lua_state(), r.stack_index()) {}; - thread(stack_reference&& r) : thread(r.lua_state(), r.stack_index()) {}; - thread& operator=(const thread&) = default; - thread& operator=(thread&&) = default; - template >>, meta::neg>> = meta::enabler> - thread(lua_State* L, T&& r) : thread(L, sol::ref_index(r.registry_index())) {} - thread(lua_State* L, int index = -1) : reference(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::thread); -#endif // Safety - } - thread(lua_State* L, ref_index index) : reference(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - type_assert(L, -1, type::thread); -#endif // Safety - } - thread(lua_State* L, lua_State* actualthread) : thread(L, lua_thread_state{ actualthread }) {} - thread(lua_State* L, sol::this_state actualthread) : thread(L, lua_thread_state{ actualthread.L }) {} - thread(lua_State* L, lua_thread_state actualthread) : reference(L, -stack::push(L, actualthread)) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, -1, type::thread); -#endif // Safety - lua_pop(L, 1); - } - - state_view state() const { - return state_view(this->thread_state()); - } - - bool is_main_thread() const { - int ismainthread = lua_pushthread(this->thread_state()); - lua_pop(this->thread_state(), 1); - return ismainthread == 1; - } - - lua_State* thread_state() const { - auto pp = stack::push_pop(*this); - lua_State* lthread = lua_tothread(lua_state(), -1); - return lthread; - } - - thread_status status() const { - lua_State* lthread = thread_state(); - thread_status lstat = static_cast(lua_status(lthread)); - if (lstat != thread_status::ok && lua_gettop(lthread) == 0) { - // No thing on the thread's stack means its dead - return thread_status::dead; - } - return lstat; - } - - thread create() { - return create(lua_state()); - } - - static thread create(lua_State* L) { - lua_newthread(L); - thread result(L); - lua_pop(L, 1); - return result; - } - }; -} // sol - -// end of sol/thread.hpp - -namespace sol { - class coroutine : public reference { - private: - call_status stats = call_status::yielded; - - void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) { -#if SOL_LUA_VERSION < 502 - stats = static_cast(lua_resume(lua_state(), static_cast(argcount))); -#else - stats = static_cast(lua_resume(lua_state(), nullptr, static_cast(argcount))); -#endif // Lua 5.1 compat - } - - template - auto invoke(types, std::index_sequence, std::ptrdiff_t n) { - luacall(n, sizeof...(Ret)); - return stack::pop>(lua_state()); - } - - template - Ret invoke(types, std::index_sequence, std::ptrdiff_t n) { - luacall(n, 1); - return stack::pop(lua_state()); - } - - template - void invoke(types, std::index_sequence, std::ptrdiff_t n) { - luacall(n, 0); - } - - protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { - int stacksize = lua_gettop(lua_state()); - int firstreturn = (std::max)(1, stacksize - static_cast(n)); - luacall(n, LUA_MULTRET); - int poststacksize = lua_gettop(lua_state()); - int returncount = poststacksize - (firstreturn - 1); - if (error()) { - return protected_function_result(lua_state(), lua_absindex(lua_state(), -1), 1, returncount, status()); - } - return protected_function_result(lua_state(), firstreturn, returncount, returncount, status()); - } - - public: - coroutine() noexcept = default; - coroutine(const coroutine&) noexcept = default; - coroutine(coroutine&&) noexcept = default; - coroutine& operator=(const coroutine&) noexcept = default; - coroutine& operator=(coroutine&&) noexcept = default; - template , coroutine>>, std::is_base_of>> = meta::enabler> - coroutine(T&& r) : reference(std::forward(r)) {} - coroutine(lua_nil_t r) : reference(r) {} - coroutine(const stack_reference& r) noexcept : coroutine(r.lua_state(), r.stack_index()) {} - coroutine(stack_reference&& r) noexcept : coroutine(r.lua_state(), r.stack_index()) {} - template >>, meta::neg>> = meta::enabler> - coroutine(lua_State* L, T&& r) : coroutine(L, sol::ref_index(r.registry_index())) {} - coroutine(lua_State* L, int index = -1) : reference(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - stack::check(L, index, type_panic); -#endif // Safety - } - coroutine(lua_State* L, ref_index index) : reference(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - stack::check(L, -1, type_panic); -#endif // Safety - } - - call_status status() const noexcept { - return stats; - } - - bool error() const noexcept { - call_status cs = status(); - return cs != call_status::ok && cs != call_status::yielded; - } - - bool runnable() const noexcept { - return valid() - && (status() == call_status::yielded); - } - - explicit operator bool() const noexcept { - return runnable(); - } - - template - protected_function_result operator()(Args&&... args) { - return call<>(std::forward(args)...); - } - - template - decltype(auto) operator()(types, Args&&... args) { - return call(std::forward(args)...); - } - - template - decltype(auto) call(Args&&... args) { - push(); - int pushcount = stack::multi_push(lua_state(), std::forward(args)...); - return invoke(types(), std::make_index_sequence(), pushcount); - } - }; -} // sol - -// end of sol/coroutine.hpp - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#elif defined _MSC_VER -#pragma warning( push ) -#endif // g++ - -#ifdef SOL_INSIDE_UNREAL -#ifdef SOL_INSIDE_UNREAL_REMOVED_CHECK -#if DO_CHECK -#define check(expr) { if(UNLIKELY(!(expr))) { FDebug::LogAssertFailedMessage( #expr, __FILE__, __LINE__ ); _DebugBreakAndPromptForRemote(); FDebug::AssertFailed( #expr, __FILE__, __LINE__ ); CA_ASSUME(false); } } -#else -#define check(expr) { CA_ASSUME(expr); } -#endif -#endif -#endif // Unreal Engine 4 Bullshit - -#endif // SOL_HPP -// end of sol.hpp - -#endif // SOL_SINGLE_INCLUDE_HPP diff --git a/contrib/lua/sol_changes.txt b/contrib/lua/sol_changes.txt deleted file mode 100644 index 10d9ec46afd..00000000000 --- a/contrib/lua/sol_changes.txt +++ /dev/null @@ -1,8 +0,0 @@ -In order to user sol with non-installed Lua version these changes are -required to the sol.hpp file: - -Around line 800 #include needs to be replaced with: -#ifndef lua_h -#include -#endif - diff --git a/doc/angelscript_primer.md b/doc/angelscript_primer.md new file mode 100644 index 00000000000..b4f75668f80 --- /dev/null +++ b/doc/angelscript_primer.md @@ -0,0 +1,78 @@ +AngelScript Primer +================== + +The following is a very brief and incomplete overview of AngelScript's syntax and some +of its quirks. This is mostly meant for programmers already familiar with at +least one other programming language, but unfamiliar with AngelScript. + +AngelScript syntax is very similar to C++ so knowing that helps. + +- [Official manual](http://www.angelcode.com/angelscript/sdk/docs/manual/index.html) +- [Leviathan AngelScript documentation](https://leviathanengine.com/doc/develop/Documentation/html/d0/db5/angelscript_main.html) + +Note: AngelScript doesn't support trailing commas so don't add a comma +after the last item in a list. + +Working With Scripts +-------------------- + +At application startup, Thrive parses the specific module files in the +build/bin/Script folder. To move your edited scripts there run `cmake +..` in `thrive/build` folder. The microbe stage module is specified in +`scripts/microbe_stage/microbe_stage.levgm`. + +There will be at some point script reloading during runtime when they +change. But it isn't currently finished and doesn't work properly. To +apply changes in the scripts, you have to restart the application. + +Within AngelScript, you have access to all classes exposed by Thrive. + + +Variables +--------- + +```cpp + // Easy as pie + float variable = 3.1415f; + + // Variables are initialized automatically + int i; + Event@ event; + + assert(event is null); + assert(i == 0); +``` + +Dictionaries +------------ + +```cpp + dictionary myTable = { + {"key1", 1}, + {"key 2", GenericEvent("some event")} + }; + + // Iterate over all entries in a table + auto keys = myTable.getKeys(); + for(uint i = 0; i < keys.length(); ++i){ + doSomething(myTable[keys[i]]); + } +``` + + +Handles and References +--------------------- + +TODO: write about this + +```cpp +MicrobeComponent@ thisIsAHandle; + +// Handles are compared with the 'is' operator (this is like pointer address comparison in C++) +if(thisIsAHandle is other){ +} + +// And they are assigned with @. If you get errors about missing assignment operator then try this! +@thisIsAHandle = other; + +``` diff --git a/doc/clang_format.md b/doc/clang_format.md new file mode 100644 index 00000000000..683220d70e2 --- /dev/null +++ b/doc/clang_format.md @@ -0,0 +1,17 @@ +Using Clang Format +================== + +To use clang format you must first install clang. On windows you +should use the clang installers and then edit your path so that the +installed folder with `clang-format.exe` is added to path. You can +optionally install visual studio integration for clang format. + +On Linux use your package manager to install clang it will also +include clang-format. If not search your os's repository for the +package that has clang-format. + +Once installed you can run `clang-format -i filename` on a thrive +source file, which should automatically find Thrive's clang format +options and format it correctly. But the recommended way is to install +a plugin for your editor to run it with a hotkey or automatically on +save. diff --git a/doc/engine_overview.dox b/doc/engine_overview.dox deleted file mode 100644 index ac2bc8037f3..00000000000 --- a/doc/engine_overview.dox +++ /dev/null @@ -1,121 +0,0 @@ -namespace thrive { /** - -@page engine_overview Engine Overview - -This page gives an overview of the most important systems and components -and how they fit together. It is meant for prospective contributors trying to -get a grasp on how the engine works. - -This document assumes that you have an understanding of -@ref entity_component "entities, components and systems" - -@section graphics Graphics - -Thrive uses the Ogre3D graphics engine for rendering. Rendering is done as one -of the last things in each frame. The most notable systems are listed here. - -@subsection scene_nodes Scene Nodes - -Everything that has a position and orientation in the game world has an -associated Ogre::SceneNode. - -The three systems OgreAddSceneNodeSystem, OgreRemoveSceneNodeSystem and -OgreUpdateSceneNodeSystem work in conjunction to add, remove and update -the underlying Ogre::SceneNode for entities that have an -OgreSceneNodeComponent. - -Many graphics-related components only work if their entity also has an -OgreSceneNodeComponent. - -You can "attach" a scene node (i.e. make its transformation relative) to -a parent by setting OgreSceneNodeComponent::m_parentId. - -Scene nodes can optionally display a 3D mesh at their position by assigning -the mesh's resource name to OgreSceneNodeComponent::m_meshName. Assign an -empty string (the default value) to display nothing. - -#### Example (Lua) -@include scene_node.lua - - -@subsection cameras_viewports Cameras and Viewports - -The OgreCameraSystem filters for entities with both an OgreSceneNodeComponent -and an OgreCameraComponent. - -To make a camera's viewpoint visible, it must be attached to a viewport. -Viewports can be created by creating an entity and giving it at least an -OgreViewportComponent. By assigning a camera entity to the -OgreViewportComponent::Properties::cameraEntity field of -OgreViewportComponent::m_properties, the viewport will show what the camera -sees. - -#### Example (Lua) -@include camera_viewport.lua - - -@subsection lights Lights - -The OgreLightSystem filters for entities with both an OgreSceneNodeComponent -and an OgreLightComponent. - -#### Example (Lua) -@include light.lua - - -@section input Input - -Mouse and keyboard input are handled by the OIS (Open Input System) library. -The input states can be queried from the MouseSystem and KeyboardSystem. In -Lua, those systems are accessible through the `Engine` global. - -The mouse position can be queried as absolute pixels or normalized from 0.0 to -1.0 relative to the window's dimensions. - -#### Example (Lua) -@include input.lua - - -@section physics Physics - -For physics, we use the Bullet library. Rigid bodies are created by adding a -RigidBodyComponent to an entity. The RigidBodyInputSystem updates the -underlying btRigidBody object with the properties set in the -RigidBodyComponent, while the RigidBodyOutputSystem reads the results of the -physics simulation and writes them back into the RigidBodyComponent. - -If an entity has both an OgreSceneNodeComponent and a RigidBodyComponent, the -authority on the position and orientation is the RigidBodyComponent. The -BulletToOgreSystem will update the transform of the OgreSceneNodeComponent -each frame. - - -#### Example (Lua) - -@include rigid_body.lua - - -@section scripting Scripting - -To avoid frequent recompilation for minor tweaks, Thrive uses Lua scripts to -supplement the C++ code. To expose C++ functions and classes to Lua, we use -the luabind library. - -Lua scripts have access to a global `Engine`. See Engine::luaBindings() for -an overview of that object's functions and properties. - -The primary mechanism for extending Thrive via Lua scripts is to derive from -the Component and System class. Lua-defined systems can then be added with a -call to Engine::addScriptSystem. You can use the EntityFilter to extract the -list of relevant entities for your system. - -#### Defining a new component in Lua - -@include component.lua - - -#### Defining a new system in Lua - -@include system.lua - -*/ } diff --git a/doc/engine_overview.md b/doc/engine_overview.md new file mode 100644 index 00000000000..d675b99efc3 --- /dev/null +++ b/doc/engine_overview.md @@ -0,0 +1,64 @@ +Engine Overview +=============== + +This page gives an overview of the most important systems and components +and how they fit together. It is meant for prospective contributors trying to +get a grasp on how the engine works. + +This document assumes that you have an understanding of [entities, components and systems](entity_component.md) + +Graphics +-------- + +Thrive uses the Ogre3D graphics engine for rendering. Rendering is done as one +of the last things in each frame. The most notable systems are listed here. + +### Scene Nodes + +Everything that has a position and orientation in the game world has an +associated Ogre::SceneNode. + +The two components Position and RenderNode work in conjunction to add, remove and update +the underlying Ogre::SceneNode for entities. + +Many graphics-related components only work if their entity also has an +RenderNode. + +You can "attach" a scene node (i.e. make its transformation relative) +to a parent by calling Ogre::SceneNode::removeFromParent (on the +child) and Ogre::SceneNode::addChild (on the parent). + +Scene nodes can optionally display a 3D mesh at their position by +creating a Model component. + +Input +----- + +Mouse and keyboard input are handled by SDL2 in Leviathan engine. See +the engine documentation for the input classes (note: currently this +is quite lacking, help writing this is welcome) + +Physics +------- + +For physics, we use the Newton dynamics library. Rigid bodies are +created by adding a Physics component to an entity. The physics system +then updates the entity's Position based on the physics simulation. + +The authority on the position and orientation is the Physics component. + +Scripting +--------- + +To avoid frequent recompilation for minor tweaks, Thrive uses AngelScript to +supplement the C++ code. To expose C++ functions and classes to scripts they need to be registered to the AngelScript engine. + +Scripts have access to a global `GetEngine()` and +`GetThriveGame()`. See the binding functions for what you can call. + +The primary mechanism for extending Thrive via scripts is to derive +from the ScriptComponent and ScriptSystem class. AngelScript-defined +systems can then be added with a call to +GameWorld::RegisterScriptSystem and +GameWorld::RegisterScriptComponentType. See the AngelScript primer for +how AngelScript systems can get relevant components. diff --git a/doc/entity_component.dox b/doc/entity_component.dox deleted file mode 100644 index 0979914c7b7..00000000000 --- a/doc/entity_component.dox +++ /dev/null @@ -1,63 +0,0 @@ -namespace thrive { /** - -@page entity_component Entities, Components and Systems - -Introductions to the entity / component approach can be found here: - - Entity / Component Game Design: A Primer - - Game Engines 101: The Entity / Component Model - - What is an entity system framework? - -The following gives an overview of the implementation of entities, -components and systems in Thrive. - -@section entity_manager Entity Manager - -Entities and their components are managed by an EntityManager. The -EntityManager identifies each entity by its unique id. You can use -either EntityManager::generateNewId() or EntityManager::getNamedId() -to obtain an id. - -An entity can have at most one component of each type. Component types are -distinguished primarily by their component id (see also -Component::generateTypeId()). This component id is generated dynamically -at application startup and may change between executions. To identify a -component type across executions, use the component name, which -should be constant between executions. To convert between component id -and component name, use ComponentFactory::typeNameToId() and -ComponentFactory::typeIdToName(). - -For convenience, there's an Entity class that wraps the API of -EntityManager in an entity-centric way. - -@section system Systems - -The absolute minimum a system has to implement is the System::update() -function. You can also override System::init() and System::shutdown() for -setup and teardown procedures. - -Usually, a system operates on entities that have a specific combination of -components. The EntityFilter template can filter out entities that have -such a component makeup. - -@section game_state GameState - -Game states represent a distinct state of the game with its own systems and -entities. Examples for such a state are "main menu", "microbe stage" or -"microbe editor". - -All systems are managed by a game state. The game state provides an entity -manager, initializes its systems, updates them during the game and -finally, shuts them down. - -Game states are indirectly created by Engine::addGameState(). A state's -system list cannot be changed after creation. - -@section engine Engine - -Engine is for GameState what GameState is for System. It holds a list of -registered game states. During startup the game states are all initialized. -During runtime, the current game state is updated. When the game exits, the -engine shuts each game state down. - - -*/ } diff --git a/doc/entity_component.md b/doc/entity_component.md new file mode 100644 index 00000000000..c2d6a8f2259 --- /dev/null +++ b/doc/entity_component.md @@ -0,0 +1,50 @@ +Entities, Components and Systems +================================ + +Introductions to the entity / component approach can be found here: + - [Entity / Component Game Design: A Primer](http://piemaster.net/2011/07/entity-component-primer/) + - [Game Engines 101: The Entity / Component Model](http://www.gamasutra.com/blogs/MeganFox/20101208/88590/Game_Engines_101_The_EntityComponent_Model.php) + - [What is an entity system framework?](http://www.richardlord.net/blog/what-is-an-entity-framework) + +The following gives an overview of the implementation of entities, +components and systems in Thrive. + +GameWorld +--------- + +Entities and their components are managed by a GameWorld (microbe +stage uses CellStageWorld). The GameWorld identifies each entity by +its unique id. You can use GameWorld::CreateEntity() to obtain an +id. Don't forget to call GameWorld::QueueDestroyEntity when the entity +should be destroyed. This delayed destruction is used to aboid +problems with destroying components that are currently used during a +run. + +An entity can have at most one component of each type. Component types +are distinguished by their C++ class or name if they are defined in +ANgelScript. To identify a component type C++ classes have a `TYPE` +member. + +GameWorld represent a distinct state of the game with its own systems and +entities. Examples for such a are "microbe stage" and "microbe editor". + +All systems are managed by a GameWorld. The GameWorld provides entity +management, initializes its systems, updates them during the game and +finally, shuts them down. + +GameWorlds are created in ThriveGame during setup. + +Systems +------- + +The absolute minimum a system has to implement is the Run(Leviathan::GameWorld& world) method +function. You can also add a constructor and a destructor for +setup and teardown procedures. + +Usually, a system operates on entities that have a specific +combination of components. Inheriting from Leviathan::System and +implementing CreateNodes and DestroyNodes allows systems to keep track +of entities that have their required components. AngelScript systems +can use CreateAndDestroyNodes and use the helper function +ScriptSystemNodeHelper. + diff --git a/doc/lua_primer.dox b/doc/lua_primer.dox deleted file mode 100644 index b24284015ee..00000000000 --- a/doc/lua_primer.dox +++ /dev/null @@ -1,142 +0,0 @@ -/** -\page lua_primer Lua Primer - -The following is a very brief and incomplete overview of Lua's syntax and some -of its quirks. This is mostly meant for programmers already familiar with at -least one other programming language, but unfamiliar with Lua. - -If you want to know more about Lua, any of the following links is a good start: - -- The briefest introduction to Lua -- Lua 5.2 Reference Manual -- Lua Wiki Tutorials - -Variables ---------- - -\code{.lua} - -- Easy as pie - variable = 3.1415 - - -- Local variables are preferred. They keep the global scope clean - -- and are a bit faster for access. - local localVariable = 42 - - -- Undefined variables are nil by default - assert(idontexist == nil) -\endcode - - -Tables ------- - -\code{.lua} - local myTable = { - 1 = "number", - key = "value", - ["Key with spaces"] = "anotherValue", -- Note the (optional) trailing comma - } - - -- The following two lines are equivalent - myTable.a = "Thrive" - myTable["a"] = "Thrive" - - -- To remove an item, assign nil: - myTable.key = nil - - -- Arrays are just tables with numeric keys - local myArray = { - "first", - "second", - "third", - 4, - 5, - 6 - } - - -- Indices start at 1, not 0 - assert(myArray[1] == "first") - - -- Accessing non-existant keys gives back nil - assert(myArray[0] == nil) - assert(myTable.nosuchkey == nil) - -\endcode - - -Functions and Classes ---------------------- -\code{.lua} - function myFunction(x, y) - return x + y - end - - -- Functions, just like variables, should be declared local where possible - local function myLocalFunction(x, y) - return x - y - end - - -- Functions without a return implicitly return nil - local function returnsNil() - end - assert(returnsNil() == nil) - - -- Classes are not a standard Lua feature, but the luabind library - -- enables them for us - class 'MyClass' - - -- Note the colon - function MyClass:__init(x) - self.x = x - end - - function MyClass:doSomething() - print("My x is " .. tostring(self.x)) - end - - local myObject = MyClass(5) - assert(myObject.x == 5) - - -- A word about this strange colon: The following three lines are equivalent - myObject:doSomething() - myObject.doSomething(myObject) - MyClass.doSomething(myObject) - - -- As are these two definitions - function MyClass:doMore() - return 5 - end - - function MyClass.doMore(self) - return 5 - end - -\endcode - - - -Control Structures ------------------- - -\code{.lua} - if condition then - doSomething() - end - - -- Loop over numbers - for i=min,max,step do - doSomething(i) - end - - -- Iterate over all entries in a table - for key, value in pairs(table) do - doSomething(key, value) - end - - -- Iterate over the consecutive numeric entries in a table - for i, value in ipairs(table) do - doSomething(i, value) - end -\endcode - -*/ diff --git a/doc/main.dox b/doc/main.dox deleted file mode 100644 index f5a83e4b702..00000000000 --- a/doc/main.dox +++ /dev/null @@ -1,21 +0,0 @@ -namespace thrive { /** - -@mainpage Thrive API documentation - -This is the API documentation for the Thrive source code, targetted -at new developers (both C++ and Lua) and old developers that tend to forget -what they have written a couple of weeks ago. - -When (not if) you find anything that is unclear or is missing, please post -a thread about it in the -Thrive development forums. - -If you are still reading, chances are that you seek information on a -specific topic. Apart from the raw API, this documentation currently offers -advice on: -- @ref entity_component -- @ref engine_overview -- @ref scripting_thrive - - -*/} diff --git a/doc/quicktips.md b/doc/quicktips.md index d48aa93ddf4..e1bd1ceb26e 100644 --- a/doc/quicktips.md +++ b/doc/quicktips.md @@ -1,27 +1,12 @@ -#Quick Tips for Navigating the Source +Quick Tips for Navigating the Source +==================================== -Most current work happens in Lua, with C++ development generally providing little more than interfaces to CEGUI, Ogre, and all the other parts of the engine. +Most current work happens in AngelScript, with C++ development generally providing little more than interfaces to CEGUI, Ogre, and all the other parts of the engine and some gameplay systems. -Before you begin, Google "Ogre3D", "CEGUI", "luabind", and "Entity Component System" so you know what they are. +Before you begin, Google "Ogre3D", "CEGUI", and "Entity Component System" so you know what they are. And check out the [Leviathan manual](https://leviathanengine.com/doc/develop/Documentation/html/index.html) that has the documentation for the engine classes and some documentation on classes exposed to AngelScript. -*Last Updated: Dec 27, 2014 +*Last Updated: March 18, 2018 -#Lua -* Lua files are loaded into the engine in the order specified in the manifests. - * So, for any two files, the second one implicitly includes the first. -* The main_menu, microbe_stage, and microbe_editor each have some structure in common: - * The foo_hud.lua file defines the interactions with the GUI. - * Each defines a FooHudSystem, simple ECS Systems that have no components (yet, anyway). - * The :init method runs on program startup, and in these Systems sets up the callbacks for each button, and maybe saves a bit of extra state. - * The :update method runs every turn of the game loop - * See src/gui/CEGUIWindow.h for more details on the CEGUI features we currently have a Lua interface for. - * Each folder also has a setup.lua file, which, naturally, does necessary setup for the game mode. They define two important things: - * The necessary setup functions, that are called on startup - * a small function at the end which calls Engine:createGameState, defining: - * The Systems which will run in this GameState (and their order) - * The setup function, which for simplicity just calls the functions defined above -* The rest of the files in the subfolders contain more specific bits of functionality: - * Organelles are defined in microbe_stage/, each file defining a class for a certain type of organelle, and factory functions for all the different organelles of that type. - * Organelles are created by calling OrganelleFactory:makeOrganelle(data) -- the OrganelleFactory takes care of finding the right function - * The code for Microbes is overall currently a bit messy, and will probably change soon. -* The other files not in a subfolder define more general utility things -- hex coordinate math, lua interpretation in the in-game console, etc. Read as you need. +#Script +* Organelles are defined in microbe_stage/, each file defining a class for a certain type of organelle, and factory functions for all the different organelles of that type. + * Organelles are created by calling `PlacedOrganelle(getOrganelleDefinition("name"), q, r, rotation)` diff --git a/doc/scripting.dox b/doc/scripting.dox deleted file mode 100644 index ebe5180603a..00000000000 --- a/doc/scripting.dox +++ /dev/null @@ -1,26 +0,0 @@ -namespace thrive { /** - -@page scripting_thrive Scripting Thrive - -Thrive is scriptable with the Lua script language. A short primer can be -found \ref lua_primer "here". - -At application startup, Thrive parses the file \c scripts/manifest.txt. Each -line of this file should be either a filename or a directory name. If it's -a file name, the file is executed with Lua. For directories, Thrive goes -down into this directory and looks for another manifest.txt, applying the -same procedure recursively. You can make Thrive ignore a line in a manifest -by starting the line with two forward-slashes: "//". - -There is currently no way to reparse the scripts at runtime and it is -doubtful there ever will be. To apply changes in the scripts, you have to -restart the application. - -Within the Lua scripts, you have access to all classes exposed by Thrive. -The most important one is probably Entity. Then, there are the subclasses of -Component and the System class. If you want to know more about the script API -of these classes, look for the function \c luaBindings() -(e.g. Entity::luaBindings()), it will list the functions and data members -that are exposed to Lua. - -*/} diff --git a/doc/setup_instructions.md b/doc/setup_instructions.md new file mode 100644 index 00000000000..7134c35cd1b --- /dev/null +++ b/doc/setup_instructions.md @@ -0,0 +1,141 @@ +What's this? +============ + +This is the setup instructions for compiling Thrive. + +Important Note: If you run into any trouble with the setup scripts, please +bring them up on the development slack or open a github issue. + +If you are a team member you can ask help on the forums: + [Private Developer Forums](http://forum.revolutionarygamesstudio.com/) + +Thank you! + +Prerequisites +============= + +10 GiB of disk space and about 60 minutes of compile time on a good CPU. + +Follow the Leviathan Engine Prequisites installation instructions +[here](https://leviathanengine.com/doc/develop/Documentation/html/dc/d9e/prerequisites.html). + +Important: you should read the whole document before starting as many +common pitfalls and issues have fixes given after later in the document. Also DO +NOT SKIP ANY STEPS otherwise you will initially fail and have to clear +the caches which is the easiest to do by just deleting the entire +folder and starting again. When you are done with the prerequisites +page return here instead of continuing to the building Leviathan page +which is irrelevant for Thrive. + +Building Thrive +=============== + +Clone +----- + +Open a terminal on linux or a command prompt (or powershell) on windows to a folder where you want to place the Thrive folder. + +Note: a path with spaces in it WILL NOT WORK, so to avoid issues you +should choose a folder like `~/projects` or `C:/projects`. Also long +paths don't work on Windows as the setup needs the path in which it is +ran to be less than 90 characters, so choose run git clone in +`C:\projects` so that you end up the thrive folder being +`C:\projects\Thrive`. + +Windows tip: shift right-click in a folder and select "Open command +prompt here" or "Open powershell here" to open a cmd window to the +folder + +And now run + +``` +git clone https://github.com/Revolutionary-Games/Thrive.git +cd Thrive +``` + +To get the Thrive repository cloned. + +For devs working on engine changes: switch to the engine_refactor +branch with `git checkout engine_refactor`. Or to another branch you +want to work on. This keeps the main branch clean as other branches +can be merged through pull requests on github which is the recommended +way to get your code into Thrive. + +If you aren't on the team (have push access on github) create a fork +on github and use the url of that instead of the one above. + + +Running Setup +------------- + +Now you can run the setup script with (make sure you have setup prerequisites): + +``` +ruby SetupThrive.rb thrive +``` + +The last part of the command (thrive) is the svn username. If you have +an svn assets username (ask on slack) use it instead of "thrive" here. + +When asked to login to svn type in your svn password. Or if you are +using "thrive" as username type in "thrive" as the password as well. + +Note: if you have a small amount of ram you may want to limit the +setup script to only use a few CPU cores for building or don't want to +dedicate all of your CPU. To do this add `-j 2` to the end of the +setup command with the number being the number of cores you want to +use, the default is to use all. Note: this may not work for the +dependencies (and that needs fixing) + +Done +---- + +If the setup script succeeds then congratulations you have just +successfully built Thrive and can start working. + +If it didn't work you can try these: +- [Leviathan Troubleshoothing tips](https://leviathanengine.com/doc/develop/Documentation/html/dc/dca/compiling_leviathan.html#compile_troubleshooting) +- Thrive forums +- Thrive discord +- Thrive developer chat on slack + +to get help + +Here are some quick tips for working on thrive: + +- [Scripting + documentation](https://leviathanengine.com/doc/develop/Documentation/html/d0/db5/angelscript_main.html) +- On Windows: when building Thrive in visual studio select + `RelWithDebInfo` configuration (instead of Debug). Otherwise the build + may fail. And make sure "Thrive" is the startup project to run it in the debugger. +- Whenever you **change the assets** or scripts you need to run cmake. See + [this](https://leviathanengine.com/doc/develop/Documentation/html/df/d4e/tutorial1.html#tutorial1recompiling) + for more info + +Forking +------- + +If you are just starting out and you don't have write access to the +Thrive repository yet you will need to create a fork. Use the fork +button on Github on the main repository page. This will give you a +fork (for example my fork is https://github.com/hhyyrylainen/Thrive). + +Then you can add that to your git config in the thrive folder with this command: + +``` +git remote add fork https://github.com/YOURUSERNAMEHERE/Thrive.git +``` + +Then after committing your changes (git-cola is recommended or another +graphical tool for reviewing the exact lines you have changed, but you +can also commit on the command line) you can publish them to your fork +with (assuming you used the master branch, when working with the main +thrive repository you MUST create a different branch but when working +with a fork that isn't required): + +``` +git push fork master +``` + +Now you can open a pull request by visiting the Github page for your +fork. diff --git a/doc/style_guide.dox b/doc/style_guide.md similarity index 55% rename from doc/style_guide.dox rename to doc/style_guide.md index 900cd9d2c38..85f507d7a8c 100644 --- a/doc/style_guide.dox +++ b/doc/style_guide.md @@ -1,9 +1,9 @@ -/** -\page Code Style Guide +Code Style Guide +================ To maintain a consistent coding style, contributors should follow the rules outlined on this page. This style guide is separated into four parts: common -rules, rules specific for C++, rules specific for Lua and guidelines for +rules, rules specific for C++, rules specific for AngelScript and guidelines for using git. The style rules are intended to increase readability of the source code. The @@ -11,7 +11,8 @@ most important rule of all is: **Use common sense**. If you have to break some rules to make the code more readable (and not just for you, but for everyone who has to read your code), break it. -\section common_style Common (Both C++ and Lua) +Common (Both C++ and AngelScript) +-------------------------------------- - Indentation is 4 spaces @@ -23,21 +24,25 @@ everyone who has to read your code), break it. CamelCase with leading upper case. Constants are CONSTANT_CASE with underscores. -- Filenames are lower_case with underscores. The reason for this is that Thrive - is a cross-platform project and some platforms use case-sensitive file systems - (Unix) while others use case-insensitive file systems (Windows). Exceptions - are the CMakeLists.txt files, which need to be named like this for CMake to - find them. +- Filenames are lower_case with underscores. The reason for this is + that Thrive is a cross-platform project and some platforms use + case-sensitive file systems (Unix) while others use case-insensitive + file systems (Windows). Exceptions are the CMakeLists.txt files and + a few of the other core files, which need to be named like this for + them to work. -\section cpp_style C++ +C++ +--- - Macros are CONSTANT_CASE - Header files end in .h, source files in .cpp -- Header files should begin with #pragma once. Old-style header - guards (with \p ifdef) are discouraged because they are very verbose and +- Header files should begin with `#pragma once`. Old-style header + guards (with `ifdef`) are discouraged because they are very verbose and the pragma is understood by all relevant compilers. + +- Format your code with [clang-format](clang_format.md) - Opening braces go in the same line as the control statement, closing braces are aligned below the first character of the opening control statement @@ -58,33 +63,19 @@ everyone who has to read your code), break it. - Member variables of classes are prefixed with \p m_. This is to differentiate them from local or global variables when using their - unqualified name (without \p this->) inside member functions. The prefix can + unqualified name (without `this->`) inside member functions. The prefix can be omitted for very simple structs if they don't have member functions and serve only as data container. -- When calling member functions from another member function, their names are +(- When calling member functions from another member function, their names are qualified with `this->` to differentiate them from global non-member - functions. - -- Function signatures are formatted like this: - \code{.cpp} - [virtual] ReturnType - functionName( - ArgType1 arg1, - ArgType2 arg2 - ) [const] [override] { - // Function body - } - \endcode - This format may look strange at first, but it has some advantages over - other formats. The return type is clearly separated from the function name, - which increases readability for long, unwieldy return types (think nested - templates). Each argument is at its own line, making it possible to discern - the number of arguments and their types at a glance. Again, this increases - readability for complex argument types. - -- For non-trivial classes, use the pimpl idiom to hide implementation details. - \code{.hpp} + functions.) + +- Function signatures are formatted like the clang-format options file makes them to be formatted + +- For non-trivial classes that would pull in a lot of other headers, use the pimpl idiom to hide implem entation details and only include the ton of headers in the .cpp file. + + ```cpp // In the header: #include // Include for std::unique_ptr @@ -105,8 +96,9 @@ everyone who has to read your code), break it. struct Implementation; std::unique_ptr m_impl; }; - \endcode - \code{.cpp} + ``` + + ```cpp // In the source file: struct MyClass::Implementation { @@ -119,52 +111,83 @@ everyone who has to read your code), break it. } MyClass::~MyClass() {} // Define destructor - \endcode - -- Prefer C++11's \p using over \p typedef. With the \p using keyword, type + ``` + +- Try to avoid include statements inside header files unless + absolutely necessary. Prefer forward declarations and put the + include inside the source file instead. And use the pimpl idiom if + this cannot be avoided and the headers are large. + +- Prefer C++11's `using` over `typedef`. With the `using` keyword, type aliases look more like familiar variable assignment, with no ambiguity as to which is the newly defined type name. - Virtual member functions overridden in derived classes are marked with the - C++11 \p override keyword. This will (correctly) cause a compile time error + C++11 `override` keyword. This will (correctly) cause a compile time error when the function signature in the base class changes and the programmer forgot to update the derived class. -- Classes not intended as base classes are marked with the \p final keyword +- Classes not intended as base classes are marked with the `final` keyword like this: - \code{.cpp} + + ```cpp class MyClass final { // ... }; - \endcode + ``` -- Try to avoid include statements inside header files unless absolutely - necessary. Prefer forward declarations and put the include inside the - source file instead. +- Header includes should be split by project with an empty line + between. The order is first Thrive headers then Leviathan headers + then any other library and finally standard headers. All of these + blocks are sorted alphabetically. Example: -- Header includes should be sorted alphabetically (ignoring case) + ```cpp + #include "engine/component_types.h" + #include "engine/typedefs.h" -- Functions and data members inside classes should be sorted alphabetically, - unless this interferes with destruction order. + #include + #include + + #include + + #include + #include + ``` + +- Functions and data members inside classes should be split and ordered logically. -\section lua_style Lua +AngelScript +----------- -- A class's public data members are *not* prefixed by \p m_, unlike C++. This - is because in Lua, all member variables are accessed with their qualified - names (like self.memberVariable), so there is no need to mark them. +- A class's public data members are *not* prefixed by `m_`, unlike C++. -- A class's private data members and functions are prefixed with an - underscore. This is a convention adopted from Python's PEP8 style guide. +(This is because in AngelScript, all member variables are accessed with their qualified + names (like `this.memberVariable`), so there is no need to mark them.) -- Doxygen does not support Lua natively, but for consistency's sake, Lua +- A class's private data members and functions are declared `private` + (everything is public by default) and optionally prefixed with an + underscore. This is a convention adopted from Python's PEP8 style + guide. + +- Doxygen does not support AngelScript natively, but for consistency's sake, AngelScript classes and functions are still documented with doxygen style comments. +- For consistency with C++ adding semicolons after class declarations + is recommended, but not an error if omitted. This is one of the + biggest syntax differences of AngelScript vs C++ besides the handle + types. -\section git_style Git +Git +--- - Do not work in the master branch, always create a private feature branch if you want to edit something + +- If you don't have access to the main repository yet (you will be + granted access after your first accepted pull request) fork the + Thrive repository and work in your fork and once done open a pull + request. - If you are working on a GitHub issue, your feature branch's name should begin with the issue number, followed by an underscore, followed by a @@ -178,27 +201,26 @@ everyone who has to read your code), break it. interface. So even if you have unrelated changes within the same file, you can still separate them. -- When the master branch is updated, you should usually keep your feature - branch as-is. If you really need the new features from master, do a merge. +- When the master branch is updated, you should usually keep your + feature branch as-is. If you really need the new features from + master, do a merge. Or if there is a merge conflict preventing your + pull request from being merged. - When a feature branch is done, open a pull request on GitHub so that others can review it. Chances are that during this review, there will still be issues to be resolved before the branch can be merged into master. -- To keep master's commit history clean, your commits in the feature branch - will have to be "squashed" into one single (or at least very few) commit. - It must also be rebased onto master if the master branch had any other - changes since your branch was created. To do so, use an interactive rebase, - and edit the commit message of the first feature commit, then squashing all - subsequent commits into that first one. - It is a good idea to keep the other commit messages inside the new commit's - message for future reference. +- To keep master's commit history clean, your commits in the feature + branch will have to be "squashed" into one single (or at least very + few) commit. This can be done from the Github accept pull request + button, hit the arrow to the right side and select "merge and + squash". If doing squashing manually it is a good idea to keep the + other commit messages inside the new commit's message for future + reference. -- For maintainers: GitHub requires a merge commit to recognize the merging +- For maintainers: When manually squashing GitHub requires a merge commit to recognize the merging of a pull request. A "git merge --squash" does not create a merge commit and will leave the pull request's branch "dangling". To make GitHub properly reflect the merge, follow the procedure outlined in the previous bullet point, then click the "Merge Pull Request" button on GitHub (or do a normal "git merge". - -**/ diff --git a/linux_setup/DepGlobber.rb b/linux_setup/DepGlobber.rb deleted file mode 100644 index 4e6f9899d08..00000000000 --- a/linux_setup/DepGlobber.rb +++ /dev/null @@ -1,62 +0,0 @@ -# A really hacky way to find libraries to link to by globbing -# all matching file names -require_relative 'RubySetupSystem' - - -class Globber - def initialize(libname, path) - # Force libName to be an array - if libname.kind_of?(Array) - @LibName = Array.new + libname - else - @LibName = [libname] - end - @Path = path - - @foundStatus = Array.new - # This will contain all the files that were found - @foundPaths = Array.new - end - - attr_reader :LibName - - # Runs the globber. Returns true if all were found, false if not - def run() - - @LibName.each do |lib| - info "Looking for library #{lib}" - @foundStatus.push findLibrary(lib) - end - - @foundStatus.each do |found| - if not found - return false - end - end - - info "All libraries found" - true - end - - def findLibrary(filename) - - extension = File.extname filename - - Dir.glob("#{@Path}/**/*#{extension}") do |file| - if File.basename(file) == filename - info "Found lib: #{file}" - @foundPaths.push file - return true - end - end - - warning "library #{filename} not found in path: #{@Path}" - # not found - false - end - - def getResult() - @foundPaths - end -end - diff --git a/linux_setup/RubyCommon.rb b/linux_setup/RubyCommon.rb deleted file mode 100644 index 8ab48b7574f..00000000000 --- a/linux_setup/RubyCommon.rb +++ /dev/null @@ -1,53 +0,0 @@ -# Common ruby functions -require 'os' -require 'colorize' - -# To get all possible colour values print String.colors -#puts String.colors - -# Error handling -def onError(errordescription) - - puts ("ERROR: " + errordescription).red - exit 1 -end - -# Coloured output -def info(message) - puts message.to_s.colorize(:light_blue) -end -def success(message) - puts message.to_s.colorize(:light_green) -end -def warning(message) - puts message.to_s.colorize(:light_yellow) -end -def error(message) - puts message.to_s.colorize(:red) -end - - - -# Platform detection, for library suffix -if OS.linux? - - BuildPlatform = "linux" - -elsif OS.windows? - - BuildPlatform = "windows" - -elsif OS.mac? - # Shouldn't be any file names that are different - BuildPlatform = "linux" -else - abort "Unknown OS type" -end - -# Runs a command and calls onError if it fails -def systemChecked(command) - - system command - onError "Command '#{command}' failed" if $?.exitstatus > 0 - -end diff --git a/linux_setup/RubySetupSystem.rb b/linux_setup/RubySetupSystem.rb deleted file mode 100644 index 28d47cba457..00000000000 --- a/linux_setup/RubySetupSystem.rb +++ /dev/null @@ -1,1556 +0,0 @@ -# coding: utf-8 -# A ruby script for downloading and installing C++ project dependencies -# Made by Henri Hyyryläinen - -# TODO: make cmake use extra find paths on windows and test - -require_relative 'RubyCommon.rb' -require_relative 'DepGlobber.rb' - -require 'fileutils' -require 'etc' -require 'os' -require 'pathname' - -# Used by: verifyVSProjectRuntimeLibrary -require 'nokogiri' if OS.windows? -# Required for installs on windows -require 'win32ole' if OS.windows? - - -### Setup variables -CMakeBuildType = "RelWithDebInfo" -CompileThreads = Etc.nprocessors - -# If set to true will install CEGUI editor -# Note: this doesn't work -InstallCEED = false - -# If set to false won't install libs that need sudo -DoSudoInstalls = true - -# If true dependencies won't be updated from remote repositories -SkipPullUpdates = false - -# If true skips all dependencies -OnlyMainProject = false - -# If true skips the main project -OnlyDependencies = false - -# If true new version of depot tools and breakpad won't be fetched on install -NoBreakpadUpdateOnWindows = false - -# On windows visual studio will be automatically opened if required -AutoOpenVS = true - -# Visual studio version on windows, required for forced 64 bit builds -VSVersion = "Visual Studio 14 2015 Win64" -VSToolsEnv = "VS140COMNTOOLS" - -# TODO create a variable for running the package manager on linux if possible - -### Commandline handling -# TODO: add this - - -# This verifies that CurrentDir is good and assigns it to CurrentDir -CurrentDir = checkRunFolder Dir.pwd - -ProjectDir = projectFolder CurrentDir - -ProjectDebDir = File.join ProjectDir, "libraries" - -ProjectDebDirLibs = File.join ProjectDebDir, "lib" - -ProjectDebDirBinaries = File.join ProjectDebDir, "bin" - -ProjectDebDirInclude = File.join ProjectDebDir, "include" - - - -info "Running in dir '#{CurrentDir}'" - -if BuildPlatform == "windows" - puts "This is not properly tested so be careful" - -end - -puts "Using #{CompileThreads} threads to compile, configuration: #{CMakeBuildType}" - - - -## Install runner -class Installer - # basedepstoinstall Is an array of BaseDep derived objects that install - # the required libraries - def initialize(basedepstoinstall) - - @Libraries = basedepstoinstall - - if not @Libraries.kind_of?(Array) - onError("Installer passed something else than an array") - end - - end - - # Adds an extra library - def addLibrary(lib) - - @Libraries.push lib - end - - # Runs the whole thing - # calls onError if fails - def run() - - if not SkipPullUpdates and not OnlyMainProject - info "Retrieving dependencies" - - @Libraries.each do |x| - - x.Retrieve - - end - - success "Successfully retrieved all dependencies. Beginning compile" - end - - if not OnlyMainProject - - info "Configuring dependencies" - - @Libraries.each do |x| - - x.Setup - x.Compile - x.Install - - end - - info "Dependencies done, configuring main project" - - end - - if OnlyDependencies - - success "All done. Skipping main project" - exit 0 - end - - - end - -end - -# Path helper -# For breakpad depot tools -class PathModifier - def initialize(newpathentry) - - @OldPath = ENV["PATH"] - - abort "Failed to get env path" if @OldPath == nil - - if BuildPlatform == "linux" - - newpath = newpathentry + ":" + @OldPath - - else - - newpath = @OldPath + ";" + newpathentry - - end - - info "Setting path to: #{newpath}" - ENV["PATH"] = newpath - - end - - def Restore() - info "Restored old path" - ENV["PATH"] = @OldPath - end -end - - -#### Windows stuff - -# Run visual studio environment configure .bat file -def bringVSToPath() - if not File.exist? "#{ENV[VSToolsEnv]}VsMSBuildCmd.bat" - onError "VsMSBuildCMD.bat is missing check is VSToolsEnv variable correct in Setup.rb" - end - "call \"#{ENV[VSToolsEnv]}VsMSBuildCmd.bat\"" -end - -# Makes sure that the wanted value is specified for all targets that match the regex -def verifyVSProjectRuntimeLibrary(projFile, matchRegex, wantedRuntimeLib) - # Very parameters - abort "Call verifyVSProjectRuntimeLibrary only on windows!" if not OS.windows? - onError "Project file: #{projFile} doesn't exist" if not File.exist? projFile - - # Load xml with nokogiri - doc = File.open(projFile) { |f| Nokogiri::XML(f) } - - doc.css("Project ItemDefinitionGroup").each do |group| - if not matchRegex.match group['Condition'] - next - end - - info "Checking that project target '#{group['Condition']}' Has RuntimeLibrary of type #{wantedRuntimeLib}" - - libType = group.at_css("ClCompile RuntimeLibrary") - - if not libType - warning "Couldn't verify library type. Didn't find RuntimeLibrary node" - next - end - - if libType.content != wantedRuntimeLib - - onError "In file '#{projFile}' target '#{group['Condition']}' "+ - "Has RuntimeLibrary of type #{libType.content} which is not #{wantedRuntimeLib}. "+ - "Please open the visual studio solution in the folder and modify the Runtime Library to be #{wantedRuntimeLib}." + - "If you don't know how google: 'visual studio set project runtime library'" - end - end - - success "All targets had correct runtime library types" -end - -def runWindowsAdmin(cmd) - shell = WIN32OLE.new('Shell.Application') - - shell.ShellExecute("ruby.exe", - "\"#{CurrentDir}/Helpers/WinInstall.rb\" " + - "\"#{cmd.gsub( '"', '\\"')}\"", - "#{Dir.pwd}", 'runas') - - # TODO: find a proper way to wait here - info "Please wait while the install script runs and then press any key to continue" - system "pause" -end - -def askToRunAdmin(cmd) - puts "." - puts "." - info "You need to open a new cmd window as administrator and run the following command: " - info cmd - info "Sorry, windows is such a pain in the ass" - system "pause" -end - -### Linux only stuff -def getLinuxOS() - - osrelease = `lsb_release -is`.strip - - onError "Failed to run lsb_release" if osrelease.empty? - - osrelease - -end - - -### Standard stuff - -# CMake configure -def runCMakeConfigure(additionalArgs) - - if BuildPlatform == "linux" - - system "cmake .. -DCMAKE_BUILD_TYPE=#{CMakeBuildType} #{additionalArgs}" - - else - - system "cmake .. -G \"#{VSVersion}\" #{additionalArgs}" - - end -end - -# Running make or msbuild -def runCompiler(threads) - - if BuildPlatform == "linux" - - system "make -j #{threads}" - - else - - #system "start \"ms\" \"MSBuild.exe\" " - # Would use this if used project.sln file: /target:ALL_BUILD - system "#{bringVSToPath} && MSBuild.exe ALL_BUILD.vcxproj /maxcpucount:#{threads} /p:Configuration=RelWithDebInfo" - - end -end - -# Running platform standard cmake install -def runInstall() - - if BuildPlatform == "linux" - - system "sudo make install" - - else - - info "Running install script as Administrator" - - # Requires admin privileges - runWindowsAdmin("#{bringVSToPath} && MSBuild.exe INSTALL.vcxproj /p:Configuration=RelWithDebInfo") - - end -end - -def runGlobberAndCopy(glob, targetFolder) - onError "globbing for library failed #{glob.LibName}" if not glob.run - - FileUtils.cp_r glob.getResult, targetFolder -end - -def isInSubdirectory(directory, possiblesub) - - path = Pathname.new(possiblesub) - - if path.fnmatch?(File.join(directory, '**')) - true - else - false - end - -end - -def createDependencyTargetFolder() - - FileUtils.mkdir_p ProjectDebDirLibs - - FileUtils.mkdir_p ProjectDebDirBinaries - - FileUtils.mkdir_p ProjectDebDirInclude - -end - - -def createLinkIfDoesntExist(source, linkfile) - - if File.exist? linkfile - return - end - - FileUtils.ln_sf source, linkfile - -end - -### Download settings ### -class BaseDep - def initialize(name, foldername) - - @Name = name - - @Folder = File.join(CurrentDir, foldername) - @FolderName = foldername - - end - - def RequiresClone - not File.exist?(@Folder) - end - - def Retrieve - info "Retrieving #{@Name}" - - Dir.chdir(CurrentDir) do - - if self.RequiresClone - - info "Cloning #{@Name} into #{@Folder}" - - if not self.DoClone - onError "Failed to clone repository" - end - - end - - if not File.exist?(@Folder) - onError "Retrieve Didn't create a folder for #{@Name} at #{@Folder}" - end - - if not self.Update - # Not fatal - warning "Failed to update dependency #{@Name}" - end - - end - - success "Successfully retrieved #{@Name}" - end - - def Update - Dir.chdir(@Folder) do - self.DoUpdate - end - end - - def Setup - info "Setting up build files for #{@Name}" - Dir.chdir(@Folder) do - if not self.DoSetup - onError "Setup failed for #{@Name}. Is a dependency missing? or some other cmake error?" - end - end - success "Successfully created project files for #{@Name}" - end - - def Compile - info "Compiling #{@Name}" - Dir.chdir(@Folder) do - if not self.DoCompile - onError "#{@Name} Failed to Compile. Are you using a broken version? or has the setup process"+ - " changed between versions" - end - end - success "Successfully compiled #{@Name}" - end - - def Install - info "Installing #{@Name}" - Dir.chdir(@Folder) do - if not self.DoInstall - onError "#{@Name} Failed to install. Did you type in your sudo password?" - end - end - success "Successfully installed #{@Name}" - end -end - - -# Copies files to a directory following all symlinks but also copying the symlinks if their -# names are different -# Also if stripfiles is true will run strip on each of the files -def copyPossibleSymlink(path, target, stripfiles = false, log = false) - - if not File.exist?(path) - warning "Skipping copying non-existant file: #{path}" if log - return - end - - info "Copying file: #{path} to #{target}" if log - - if File.lstat(path).symlink? - - link = File.join(File.dirname(path), File.readlink(path)) - - else - link = nil - end - - if link - - info "File #{path} is a symlink to #{link}" if log - - if not File.basename(link) == File.basename(path) - - # Symlink target has a different name, so copy the symlink - #FileUtils.cp path, target - linkname = File.join(target, File.basename(path)) - FileUtils.ln_sf File.basename(link), linkname - - if not File.lstat(linkname).symlink? - onError "Link creation failed (#{linkname} => #{File.basename(link)})" - end - - info "Created symlink #{linkname} pointing to #{File.basename(link)}" if log - end - - # Follow the link - info "Following symlink to #{link}" if log - copyPossibleSymlink(link, target, stripfiles, log) - - else - - info "Copying plain file: #{path}" if log - - # Plain old file - FileUtils.cp path, target - - if stripfiles - system "strip #{File.join(target, File.basename(path))}" - info "Stripped file #{File.join(target, File.basename(path))}" if log - end - end -end - -HandledLibraries = [] - -# Copies a dependency library to target directory following all symlinks along the way -# Ignores some common things that CMake adds that aren't actually libraries -def copyDependencyLibraries(libs, target, strip, log) - - libs.each do |lib| - - # Skip empty stuff - if not lib or lib.empty? or lib == "optimized" or lib == "debug" or lib =~ /-l.*/ - next - end - - # Skip duplicates - if HandledLibraries.include? lib - next - end - - onError "Dependency library file #{lib} doesn't exist" if not File.exists? lib - - copyPossibleSymlink(lib, target, strip, log) - HandledLibraries.push lib - - end -end - -# Finds library matching regex and returns that folder -def findLibraryFolder(libs, regex) - - libs.each do |lib| - - if lib =~ regex - - return File.dirname lib - - end - end - - "didn't find library matching regex" -end - -# Finds CEGUI plugins and adds them to the list -def findCEGUIPlugins(libs, ceguiversion) - - ceguiDir = findLibraryFolder(libs, /.*CEGUIBase.*/i) - - ceguiDir = File.join(ceguiDir, "cegui-#{ceguiversion}.0") - - if not File.exists? ceguiDir - onError "Failed to find CEGUI root directory for dynamic libs (#{ceguiDir})" - end - - info "Looking for CEGUI plugins in #{ceguiDir}" - - Dir.chdir(ceguiDir) do - - Dir["*.so"].each do |ceguilib| - - libs.push File.absolute_path(ceguilib) - - end - - end - -end - -# Finds Ogre plugins and adds them to the list -# Plugin names is an array containing names like 'RenderSystem_GL' and 'Plugin_ParticleFX' -def findOgrePlugins(libs, pluginnames) - - ogreDir = File.join(findLibraryFolder(libs, /.*OgreMain.*/i), "OGRE") - - if not File.exists? ogreDir - onError "Failed to find Ogre root directory for plugins (#{ogreDir})" - end - - pluginnames.each do |lib| - - # This is a symbolic link but the dependency copy function should figure it out - file = File.absolute_path(File.join(ogreDir, lib + ".so")) - - onError "Ogre library #{file} doesn't exist" if not File.exists? file - - libs.push file - - end - -end - -# Boost thread library is a ld script. This finds the actual libraries -def findRealBoostThread(libs) - - boostDir = findLibraryFolder(libs, /.*boost_thread.*/i) - - if not File.exists? boostDir - onError "Failed to find boost_thread directory for getting actual libraries (#{boostDir})" - end - - # Copy the actual files - Dir.chdir(boostDir) do - - Dir["libboost_thread.*"].each do |lib| - - libs.push File.absolute_path(lib) - - end - - end -end - -# Uses ldd on a file to find dependency libraries -def lddFindLibraries(binary) - - result = [] - - libs = `ldd "#{binary}"` - - libs.each_line do |line| - - line.strip! - - if line.empty? - next - end - - if match = line.match(/\s+=>\s+(.*?\.so[^\s]*)/i) - - lib = match.captures[0] - - # Skip non-existing filles - if not File.exist? lib or not Pathname.new(lib).absolute? - next - end - - if not isGoodLDDFound lib - next - end - - # And finally skip ones that are in the staging or build directory - if not isInSubdirectory(CurrentDir, lib) - - puts "ldd found library: " + lib - - result.push lib - - end - end - end - - result -end - - -# -#### Library Install Definitions ### -# These are all the libraries that this script can install -# - -class Newton < BaseDep - def initialize - super("Newton Dynamics", "newton-dynamics") - end - - def DoClone - system "git clone https://github.com/MADEAPPS/newton-dynamics.git" - $?.exitstatus == 0 - end - - def DoUpdate - system "git checkout master" - system "git pull origin master" - $?.exitstatus == 0 - end - - def DoSetup - - if BuildPlatform == "windows" - - return File.exist? "packages/projects/visualStudio_2015_dll/build.sln" - else - FileUtils.mkdir_p "build" - - Dir.chdir("build") do - - runCMakeConfigure "-DNEWTON_DEMOS_SANDBOX=OFF" - return $?.exitstatus == 0 - end - end - end - - def DoCompile - if BuildPlatform == "windows" - cmdStr = "#{bringVSToPath} && MSBuild.exe \"packages/projects/visualStudio_2015_dll/build.sln\" " + - "/maxcpucount:#{CompileThreads} /p:Configuration=release /p:Platform=\"x64\"" - system cmdStr - return $?.exitstatus == 0 - else - Dir.chdir("build") do - - runCompiler CompileThreads - - end - return $?.exitstatus == 0 - end - end - - def DoInstall - - # Copy files to ProjectDir dependencies folder - createDependencyTargetFolder - - runGlobberAndCopy(Globber.new("Newton.h", File.join(@Folder, "coreLibrary_300/source")), - ProjectDebDirInclude) - - if BuildPlatform == "linux" - - runGlobberAndCopy(Globber.new("libNewton.so", File.join(@Folder, "build/lib")), - ProjectDebDirLibs) - - else - - runGlobberAndCopy(Globber.new("newton.dll", - File.join(@Folder, "coreLibrary_300/projects/windows")), - ProjectDebDirBinaries) - - runGlobberAndCopy(Globber.new("newton.lib", - File.join(@Folder, "coreLibrary_300/projects/windows")), - ProjectDebDirLibs) - end - true - end -end - -class OpenAL < BaseDep - def initialize - super("OpenAL Soft", "openal-soft") - onError "Use OpenAL from package manager on linux" if BuildPlatform != "windows" - end - - def DoClone - system "git clone https://github.com/kcat/openal-soft.git" - $?.exitstatus == 0 - end - - def DoUpdate - system "git checkout master" - system "git pull origin master" - $?.exitstatus == 0 - end - - def DoSetup - FileUtils.mkdir_p "build" - - Dir.chdir("build") do - - runCMakeConfigure "-DALSOFT_UTILS=OFF -DALSOFT_EXAMPLES=OFF -DALSOFT_TESTS=OFF" - end - - $?.exitstatus == 0 - end - - def DoCompile - - Dir.chdir("build") do - runCompiler CompileThreads - end - $?.exitstatus == 0 - end - - def DoInstall - return false if not DoSudoInstalls - - Dir.chdir("build") do - runInstall - - if BuildPlatform == "windows" and not File.exist? "C:/Program Files/OpenAL/include/OpenAL" - # cAudio needs OpenAL folder in include folder, which doesn't exist. - # So we create it here - askToRunAdmin("mklink /D \"C:/Program Files/OpenAL/include/OpenAL\" " + - "\"C:/Program Files/OpenAL/include/AL\"") - end - end - $?.exitstatus == 0 - end -end - -class CAudio < BaseDep - def initialize - super("cAudio", "cAudio") - end - - def DoClone - #system "git clone https://github.com/R4stl1n/cAudio.git" - # Official repo is broken - system "git clone https://github.com/hhyyrylainen/cAudio.git" - $?.exitstatus == 0 - end - - def DoUpdate - system "git checkout master" - system "git pull origin master" - $?.exitstatus == 0 - end - - def DoSetup - FileUtils.mkdir_p "build" - - Dir.chdir("build") do - - if BuildPlatform == "windows" - # The bundled ones aren't compatible with our compiler setup - # -DCAUDIO_DEPENDENCIES_DIR=../Dependencies64 - runCMakeConfigure "-DCAUDIO_BUILD_SAMPLES=OFF -DCAUDIO_DEPENDENCIES_DIR=\"C:/Program Files/OpenAL\" " + - "-DCMAKE_INSTALL_PREFIX=./Install" - else - runCMakeConfigure "-DCAUDIO_BUILD_SAMPLES=OFF" - end - end - - $?.exitstatus == 0 - end - - def DoCompile - - Dir.chdir("build") do - runCompiler CompileThreads - end - $?.exitstatus == 0 - end - - def DoInstall - - Dir.chdir("build") do - if BuildPlatform == "windows" - - system "#{bringVSToPath} && MSBuild.exe INSTALL.vcxproj /p:Configuration=RelWithDebInfo" - - # And then to copy the libs - - FileUtils.mkdir_p File.join(CurrentDir, "cAudio") - FileUtils.mkdir_p File.join(CurrentDir, "cAudio", "lib") - FileUtils.mkdir_p File.join(CurrentDir, "cAudio", "bin") - - FileUtils.cp File.join(@Folder, "build/bin/RelWithDebInfo", "cAudio.dll"), - File.join(CurrentDir, "cAudio", "bin") - - FileUtils.cp File.join(@Folder, "build/lib/RelWithDebInfo", "cAudio.lib"), - File.join(CurrentDir, "cAudio", "lib") - - FileUtils.copy_entry File.join(@Folder, "build/Install/", "include"), - File.join(CurrentDir, "cAudio", "include") - - else - return true if not DoSudoInstalls - runInstall - end - end - $?.exitstatus == 0 - end -end - -class AngelScript < BaseDep - def initialize - super("AngelScript", "angelscript") - @WantedURL = "http://svn.code.sf.net/p/angelscript/code/tags/2.31.2" - - if @WantedURL[-1, 1] == '/' - abort "Invalid configuraion in Setup.rb AngelScript tag has an ending '/'. Remove it!" - end - end - - def DoClone - system "svn co #{@WantedURL} angelscript" - $?.exitstatus == 0 - end - - def DoUpdate - - # Check is tag correct - match = `svn info`.strip.match(/.*URL:\s?(.*angelscript\S+).*/i) - - abort("'svn info' unable to find URL with regex") if !match - - currenturl = match.captures[0] - - if currenturl != @WantedURL - - info "Switching AngelScript tag from #{currenturl} to #{@WantedURL}" - - system "svn switch #{@WantedURL}" - onError "Failed to switch svn url" if $?.exitstatus > 0 - end - - system "svn update" - $?.exitstatus == 0 - end - - def DoSetup - if BuildPlatform == "windows" - - return File.exist? "sdk/angelscript/projects/msvc2015/angelscript.sln" - else - return true - end - end - - def DoCompile - - if BuildPlatform == "linux" - Dir.chdir("sdk/angelscript/projects/gnuc") do - - system "make -j #{CompileThreads}" - - end - $?.exitstatus == 0 - else - - info "Verifying that angelscript solution has Runtime Library = MultiThreadedDLL" - verifyVSProjectRuntimeLibrary "sdk/angelscript/projects/msvc2015/angelscript.vcxproj", - %r{Release\|x64}, "MultiThreadedDLL" - - success "AngelScript solution is correctly configured. Compiling" - - cmdStr = "#{bringVSToPath} && MSBuild.exe \"sdk/angelscript/projects/msvc2015/angelscript.sln\" " + - "/maxcpucount:#{CompileThreads} /p:Configuration=Release /p:Platform=\"x64\"" - system cmdStr - return $?.exitstatus == 0 - end - end - - def DoInstall - - # Copy files to Project folder - createDependencyTargetFolder - - # First header files and addons - FileUtils.cp File.join(@Folder, "sdk/angelscript/include", "angelscript.h"), - ProjectDebDirInclude - - addondir = File.join(ProjectDebDirInclude, "add_on") - - FileUtils.mkdir_p addondir - - # All the addons from - # `ls -m | awk 'BEGIN { RS = ","; ORS = ", "}; NF { print "\""$1"\""};'` - addonnames = Array[ - "autowrapper", "contextmgr", "datetime", "debugger", "scriptany", "scriptarray", - "scriptbuilder", "scriptdictionary", "scriptfile", "scriptgrid", "scripthandle", - "scripthelper", "scriptmath", "scriptstdstring", "serializer", "weakref" - ] - - addonnames.each do |x| - - FileUtils.copy_entry File.join(@Folder, "sdk/add_on/", x), - File.join(addondir, x) - end - - # Then the library - if BuildPlatform == "linux" - - FileUtils.cp File.join(@Folder, "sdk/angelscript/lib", "libangelscript.a"), - ProjectDebDirLibs - - else - FileUtils.cp File.join(@Folder, "sdk/angelscript/lib", "angelscript64.lib"), - ProjectDebDirLibs - end - true - end -end - -class Breakpad < BaseDep - def initialize - super("Google Breakpad", "breakpad") - @DepotFolder = File.join(CurrentDir, "depot_tools") - @CreatedNewFolder = false - end - - def RequiresClone - if File.exist?(@DepotFolder) and File.exist?(@Folder) - return false - end - - true - end - - def DoClone - - # Depot tools - system "git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git" - return false if $?.exitstatus > 0 - - if not File.exist?(@Folder) - - FileUtils.mkdir_p @Folder - @CreatedNewFolder = true - - end - - true - end - - def DoUpdate - - if BuildPlatform == "windows" and NoBreakpadUpdateOnWindows - info "Windows: skipping Breakpad update" - if not File.exist?("src") - @CreatedNewFolder = true - end - return true - end - - # Update depot tools - Dir.chdir(@DepotFolder) do - system "git checkout master" - system "git pull origin master" - end - - if $?.exitstatus > 0 - return false - end - - if not @CreatedNewFolder - - if not File.exist?("src") - # This is set to true if we created an empty folder but we didn't get to the pull stage - @CreatedNewFolder = true - else - Dir.chdir(@Folder) do - # The first source subdir is the git repository - Dir.chdir("src") do - system "git checkout master" - system "git pull origin master" - system "gclient sync" - end - end - end - end - - true - end - - def DoSetup - - if not @CreatedNewFolder - return true - end - - # Bring the depot tools to path - pathedit = PathModifier.new(@DepotFolder) - - # Get source for breakpad - Dir.chdir(@Folder) do - - system "fetch breakpad" - - if $?.exitstatus > 0 - pathedit.Restore - onError "fetch breakpad failed" - end - - Dir.chdir("src") do - - # Configure script - if BuildPlatform == "windows" - system "src/tools/gyp/gyp.bat src/client/windows/breakpad_client.gyp –no-circular-check" - else - system "./configure" - end - - if $?.exitstatus > 0 - pathedit.Restore - onError "configure breakpad failed" - end - end - end - - pathedit.Restore - true - end - - def DoCompile - - # Bring the depot tools to path - pathedit = PathModifier.new(@DepotFolder) - - # Build breakpad - Dir.chdir(File.join(@Folder, "src")) do - - if BuildPlatform == "linux" - system "make -j #{CompileThreads}" - - if $?.exitstatus > 0 - pathedit.Restore - onError "breakpad build failed" - end - else - - info "Please open the solution at and compile breakpad client in Release and x64. " + - "Remember to disable treat warnings as errors first: "+ - "#{CurrentDir}/breakpad/src/src/client/windows/breakpad_client.sln" - - system "start #{CurrentDir}/breakpad/src/src/client/windows/breakpad_client.sln" if AutoOpenVS - system "pause" - end - end - - pathedit.Restore - true - end - - def DoInstall - - # Create target folders - FileUtils.mkdir_p File.join(CurrentDir, "Breakpad", "lib") - FileUtils.mkdir_p File.join(CurrentDir, "Breakpad", "bin") - - breakpadincludelink = File.join(CurrentDir, "Breakpad", "include") - - if BuildPlatform == "windows" - - askToRunAdmin "mklink /D \"#{breakpadincludelink}\" \"#{File.join(@Folder, "src/src")}\"" - - FileUtils.copy_entry File.join(@Folder, "src/src/client/windows/Release/lib"), - File.join(CurrentDir, "Breakpad", "lib") - - - - # Might be worth it to have windows symbols dumbed on windows, if the linux dumber can't deal with pdbs - #FileUtils.cp File.join(@Folder, "src/src/tools/linux/dump_syms", "dump_syms"), - # File.join(CurrentDir, "Breakpad", "bin") - - else - - # Need to delete old file before creating a new symlink - File.delete(breakpadincludelink) if File.exist?(breakpadincludelink) - FileUtils.ln_s File.join(@Folder, "src/src"), breakpadincludelink - - FileUtils.cp File.join(@Folder, "src/src/client/linux", "libbreakpad_client.a"), - File.join(CurrentDir, "Breakpad", "lib") - - FileUtils.cp File.join(@Folder, "src/src/tools/linux/dump_syms", "dump_syms"), - File.join(CurrentDir, "Breakpad", "bin") - - FileUtils.cp File.join(@Folder, "src/src/processor", "minidump_stackwalk"), - File.join(CurrentDir, "Breakpad", "bin") - end - true - end -end - -class Ogre < BaseDep - def initialize - super("Ogre", "ogre") - end - - def RequiresClone - if BuildPlatform == "windows" - return (not File.exist?(@Folder) or not File.exist?(File.join(@Folder, "Dependencies"))) - else - return (not File.exist? @Folder) - end - end - - def DoClone - if BuildPlatform == "windows" - - system "hg clone https://bitbucket.org/sinbad/ogre" - if $?.exitstatus > 0 - return false - end - - Dir.chdir(@Folder) do - - system "hg clone https://bitbucket.org/cabalistic/ogredeps Dependencies" - end - return $?.exitstatus == 0 - else - system "hg clone https://bitbucket.org/sinbad/ogre" - return $?.exitstatus == 0 - end - end - - def DoUpdate - - if BuildPlatform == "windows" - Dir.chdir("Dependencies") do - system "hg pull" - system "hg update" - - if $?.exitstatus > 0 - return false - end - end - end - - system "hg pull" - system "hg update v2-0" - $?.exitstatus == 0 - end - - def DoSetup - - # Dependencies compile - additionalCMake = "" - - if BuildPlatform == "windows" - Dir.chdir("Dependencies") do - - system "cmake . -DOGREDEPS_BUILD_SDL2=OFF" - - system "#{bringVSToPath} && MSBuild.exe ALL_BUILD.vcxproj /maxcpucount:#{CompileThreads} /p:Configuration=Debug" - onError "Failed to compile Ogre dependencies " if $?.exitstatus > 0 - - runCompiler CompileThreads - onError "Failed to compile Ogre dependencies " if $?.exitstatus > 0 - - info "Please open the solution SDL2 in Release and x64: "+ - "#{@Folder}/Dependencies/src/SDL2/VisualC/SDL_VS2013.sln" - - system "start #{@Folder}/Dependencies/src/SDL2/VisualC/SDL_VS2013.sln" if AutoOpenVS - system "pause" - - additionalCMake = "-DSDL2MAIN_LIBRARY=..\SDL2\VisualC\Win32\Debug\SDL2main.lib " + - "-DSD2_INCLUDE_DIR=..\SDL2\include" - "-DSDL2_LIBRARY_TEMP=..\SDL2\VisualC\Win32\Debug\SDL2.lib" - - end - end - - FileUtils.mkdir_p "build" - - Dir.chdir("build") do - - runCMakeConfigure "-DOGRE_BUILD_RENDERSYSTEM_GL3PLUS=ON " + - "-DOGRE_BUILD_RENDERSYSTEM_D3D9=OFF -DOGRE_BUILD_RENDERSYSTEM_D3D11=OFF "+ - "-DOGRE_BUILD_COMPONENT_OVERLAY=OFF " + - "-DOGRE_BUILD_COMPONENT_PAGING=OFF -DOGRE_BUILD_COMPONENT_PROPERTY=OFF " + - "-DOGRE_BUILD_COMPONENT_TERRAIN=OFF -DOGRE_BUILD_COMPONENT_VOLUME=OFF "+ - "-DOGRE_BUILD_PLUGIN_BSP=OFF -DOGRE_BUILD_PLUGIN_CG=OFF " + - "-DOGRE_BUILD_PLUGIN_OCTREE=OFF -DOGRE_BUILD_PLUGIN_PCZ=OFF -DOGRE_BUILD_SAMPLES=OFF " + - additionalCMake - end - - $?.exitstatus == 0 - end - - def DoCompile - Dir.chdir("build") do - if BuildPlatform == "windows" - system "#{bringVSToPath} && MSBuild.exe ALL_BUILD.vcxproj /maxcpucount:#{CompileThreads} /p:Configuration=Release" - system "#{bringVSToPath} && MSBuild.exe ALL_BUILD.vcxproj /maxcpucount:#{CompileThreads} /p:Configuration=RelWithDebInfo" - else - runCompiler CompileThreads - end - end - - $?.exitstatus == 0 - end - - def DoInstall - - Dir.chdir("build") do - - if BuildPlatform == "windows" - - system "#{bringVSToPath} && MSBuild.exe INSTALL.vcxproj /p:Configuration=RelWithDebInfo" - ENV["OGRE_HOME"] = "#{@Folder}/build/ogre/sdk" - - else - return true if not DoSudoInstalls - runInstall - end - end - - $?.exitstatus == 0 - end -end - -# Windows only CEGUI dependencies -class CEGUIDependencies < BaseDep - def initialize - super("CEGUI Dependencies", "cegui-dependencies") - end - - def DoClone - - system "hg clone https://bitbucket.org/cegui/cegui-dependencies" - $?.exitstatus == 0 - end - - def DoUpdate - system "hg pull" - system "hg update default" - $?.exitstatus == 0 - end - - def DoSetup - - FileUtils.mkdir_p "build" - - if InstallCEED - python = "ON" - else - python = "OFF" - end - - Dir.chdir("build") do - runCMakeConfigure "-DCEGUI_BUILD_PYTHON_MODULES=#{python} " - end - - $?.exitstatus == 0 - end - - def DoCompile - - Dir.chdir("build") do - system "#{bringVSToPath} && MSBuild.exe ALL_BUILD.vcxproj /maxcpucount:#{CompileThreads} /p:Configuration=Debug" - system "#{bringVSToPath} && MSBuild.exe ALL_BUILD.vcxproj /maxcpucount:#{CompileThreads} /p:Configuration=RelWithDebInfo" - end - $?.exitstatus == 0 - end - - def DoInstall - - FileUtils.copy_entry File.join(@Folder, "build", "dependencies"), - File.join(CurrentDir, "cegui", "dependencies") - $?.exitstatus == 0 - end -end - -# Depends on Ogre to be installed -class CEGUI < BaseDep - def initialize - super("CEGUI", "cegui") - end - - def DoClone - - system "hg clone https://bitbucket.org/cegui/cegui" - $?.exitstatus == 0 - end - - def DoUpdate - system "hg pull" - #system "hg update default" - - # TODO: allow configuring this commit - system "hg update 7f1ec2e2266e" - - $?.exitstatus == 0 - end - - def DoSetup - - FileUtils.mkdir_p "build" - - if InstallCEED - python = "ON" - else - python = "OFF" - end - - Dir.chdir("build") do - # Use UTF-8 strings with CEGUI (string class 1) - runCMakeConfigure "-DCEGUI_STRING_CLASS=1 " + - "-DCEGUI_BUILD_APPLICATION_TEMPLATES=OFF -DCEGUI_BUILD_PYTHON_MODULES=#{python} " + - "-DCEGUI_SAMPLES_ENABLED=OFF -DCEGUI_BUILD_RENDERER_DIRECT3D11=OFF -DCEGUI_BUILD_RENDERER_OGRE=ON " + - "-DCEGUI_BUILD_RENDERER_OPENGL=OFF -DCEGUI_BUILD_RENDERER_OPENGL3=OFF" - end - - $?.exitstatus == 0 - end - - def DoCompile - - Dir.chdir("build") do - runCompiler CompileThreads - end - $?.exitstatus == 0 - end - - def DoInstall - - return true if not DoSudoInstalls or BuildPlatform == "windows" - - Dir.chdir("build") do - runInstall - end - $?.exitstatus == 0 - end -end - -class SFML < BaseDep - def initialize - super("SFML", "SFML") - end - - def DoClone - system "git clone https://github.com/SFML/SFML.git" - $?.exitstatus == 0 - end - - def DoUpdate - system "git checkout master" - system "git pull origin master" - $?.exitstatus == 0 - end - - def DoSetup - FileUtils.mkdir_p "build" - - Dir.chdir("build") do - runCMakeConfigure "" - end - - $?.exitstatus == 0 - end - - def DoCompile - - Dir.chdir("build") do - - if BuildPlatform == "windows" - system "#{bringVSToPath} && MSBuild.exe ALL_BUILD.vcxproj /maxcpucount:#{CompileThreads} /p:Configuration=Debug" - end - - runCompiler CompileThreads - end - $?.exitstatus == 0 - end - - def DoInstall - - return true if not DoSudoInstalls or BuildPlatform == "windows" - - Dir.chdir("build") do - runInstall - end - $?.exitstatus == 0 - end - - def LinuxPackages - if Linux == "Fedora" - return Array["xcb-util-image-devel", "systemd-devel", "libjpeg-devel", "libvorbis-devel", - "flac-devel"] - else - onError "LinuxPackages not done for this linux system" - end - end -end - - -### LDD found libraries that should be included in full package -# Used to filter ldd results -def isGoodLDDFound(lib) - - case lib - when /.*swresample.*/i - true - when /.*vorbis.*/i - true - when /.*theora.*/i - true - when /.*opus.*/i - true - when /.*pcre.*/i - true - when /.*ogg.*/i - true - when /.*tinyxml.*/i - true - when /.*avcodec.*/i - true - when /.*avformat.*/i - true - when /.*avutil.*/i - true - when /.*swscale.*/i - true - when /.*rtmp.*/i - true - when /.*gsm.*/i - true - when /.*soxr.*/i - true - when /.*vpx.*/i - true - when /.*x2.*/i - true - when /.*libstdc++.*/i - true - when /.*jpeg.*/i - true - when /.*jxrglue.*/i - true - when /.*IlmImf.*/i - true - when /.*Imath.*/i - true - when /.*Half.*/i - true - when /.*Iex.*/i - true - when /.*IlmThread.*/i - true - when /.*openjp.*/i - true - when /.*libraw.*/i - true - when /.*png.*/i - true - when /.*freeimage.*/i - true - when /.*gnutls.*/i - true - when /.*atomic.*/i - true - when /.*zzip.*/i - true - when /.*Cg.*/i - true - when /.*va.*/i - true - when /.*xvid.*/i - true - when /.*zvbi.*/i - true - when /.*amr.*/i - true - when /.*mfx.*/i - true - when /.*aac.*/i - true - # nvidia stuff for ffmpeg - when /.*nvcu.*/i - true - when /.*cuda.*/i - true - when /.*nvidia-fatbinary.*/i - true - when /.*vdpau.*/i - true - when /.*twolame.*/i - true - when /.*h26.*/i - true - when /.*mp3.*/i - true - when /.*bluray.*/i - true - when /.*OpenCL.*/i - true - when /.*webp.*/i - true - when /.*schroedinger.*/i - true - when /.*Xaw.*/i - true - when /.*numa.*/i - true - when /.*hogweed.*/i - true - when /.*jasper.*/i - true - when /.*nettle.*/i - true - when /.*unistring.*/i - true - else - false - end -end - diff --git a/linux_setup/RunCodeIndexing.rb b/linux_setup/RunCodeIndexing.rb deleted file mode 100755 index 0737a7a3fe4..00000000000 --- a/linux_setup/RunCodeIndexing.rb +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env ruby - -require 'find' - - -if File.exists? "src" - runFolder = "." -else - runFolder = "../" -end - -Dir.chdir(runFolder){ - - file_paths = [] - Find.find('.') do |path| - file_paths << path if (not path =~ /.*\/contrib\/.*/) and - (not path =~ /.*\/build\/.*/) and ((path =~ /.*\.h/) or - (path =~ /.*\.cpp/)) - end - - File.open("cscope.files", "w") do |f| - f.puts(file_paths) - end - - system "cscope -b" -} diff --git a/linux_setup/WinInstall.rb b/linux_setup/WinInstall.rb deleted file mode 100644 index de17641f8cb..00000000000 --- a/linux_setup/WinInstall.rb +++ /dev/null @@ -1,17 +0,0 @@ -# Installs a target on Windows -# This is a separate script so that it is enough to run just this script as administrator -require_relative 'RubySetupSystem' - -abort "invalid argumenst" if ARGV.count != 1 - -info "Running install: #{ARGV[0]}" -system "#{ARGV[0]}" - -if $?.exitstatus > 0 - # Failed - error "Installation Failed!" - system "pause" - abort "error" -end - -success "Installation completed" diff --git a/linux_setup/readme.md b/linux_setup/readme.md deleted file mode 100644 index 5a234214288..00000000000 --- a/linux_setup/readme.md +++ /dev/null @@ -1,101 +0,0 @@ -What's this? -============ - -This is the setup instructions for Thrive on linux. This documentation -is written for Ubuntu and latest version of Fedora, but with slight -changes this should be usable with any linux distribution. You will -need sudo access in order to install the dependencies. - -Before starting make sure that you don't have any conflicting -libraries installed. Old versions of Ogre (pre 2.0) are known to cause -issues compiling or running the game. Also you will need a really new -version of ffmpeg. So uninstall these old versions before starting if -possible, or you will have a bad time. - - -Important Note: If you run into any trouble with the setup scripts, please -bring them up on the development slack or open a github issue. - -If you are a team member you can ask help on the forums: - [Private Developer Forums](http://forum.revolutionarygamesstudio.com/) - -Thank you! - - -Common Requirements -======================== - -You will need these for any linux distribution. It is recommended that -you install these with your package manager. Additional dependencies -will be installed by the setup script. - -* git -* SVN -* CMake -* ruby - -These ruby gems for running the setup script: - -* fileutils -* colorize -* etc -* os -* nokogiri (This is only required for the packaging script and windows users. -You need to have ruby development files installed to use this) - -If in the future the script is made to support windows then also these gems are required: - -* win32ole - -Fedora example commands ------------------------ - -These commands install the required packages on Fedora. - - sudo dnf install git cmake ruby subversion - gem install fileutils colorize etc os - - -Ubuntu example commands ------------------------ - - sudo apt-get install build-essential git cmake ruby subversion - gem install fileutils colorize etc os - - -Running the Setup Script -======================== - -0. Clone Thrive ---------------- - -If you haven't already done so you need to clone the thrive -repository. Additional dependencies will be installed alongside the -thrive directory so it is recommended to clone thrive into a -subdirectory. For example: ~/projects/thrive_build/thrive First go -to [Thrive Github][thrivegh] and click the "Clone or Download" button -to get the link for clone. And replace the url in this command with it: - - git clone git@github.com:Revolutionary-Games/Thrive.git thrive - cd thrive - git submodule update --init --recursive - -1. Run Setup ------------- - -Then go to the directory and run the setup script. - - ./SetupThrive.rb - -If you installed ruby correctly you should now be prompted for your -sudo password and then installation of extra dependencies and thrive -should begin. After the script finishes successfully you can go to the -thrive/build folder and run Thrive with ./Thrive - -2. Done -------- - -If the game starts successfully then congratulations you are now ready to develop Thrive! - - -[thrivegh]: https://github.com/Revolutionary-Games/Thrive "Revolutionary-Games/Thrive" diff --git a/mingw_setup/.gitignore b/mingw_setup/.gitignore deleted file mode 100644 index d0f6b668e74..00000000000 --- a/mingw_setup/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -test_win -test -setup-output.txt diff --git a/mingw_setup/7zip/install.ps1 b/mingw_setup/7zip/install.ps1 deleted file mode 100644 index 537f4445360..00000000000 --- a/mingw_setup/7zip/install.ps1 +++ /dev/null @@ -1,51 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######### -# 7 zip # -######### - -Write-Output "--- Installing 7 zip ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -$REMOTE_FILE="http://downloads.sourceforge.net/sevenzip/7za920.zip" - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV "temp\7zip" - -mkdir $WORKING_DIR -force | out-null - - -#################### -# Download archive # -#################### - -$DESTINATION = Join-Path $WORKING_DIR 7za.zip - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile($REMOTE_FILE, $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." -Unzip $DESTINATION $WORKING_DIR diff --git a/mingw_setup/OpenAL/install.ps1 b/mingw_setup/OpenAL/install.ps1 deleted file mode 100644 index de8b44cb4e8..00000000000 --- a/mingw_setup/OpenAL/install.ps1 +++ /dev/null @@ -1,120 +0,0 @@ -param( - [string]$MINGW_ENV -) - -########## -# OpenAL # -########## - -Write-Output "--- Installing OpenAL ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\openAl - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="http://kcat.strangesoft.net/openal-releases" - -$ARCHIVE="openal-soft-1.15.1.tar.bz2" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - -########## -# Unpack # -########## -$DESTINATION = Join-Path $WORKING_DIR "openal-soft-1.15.1.tar" - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -$BUILD_TYPES = @("Debug", "Release") - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR - - $ARGUMENTS = - "-DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE", - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "$WORKING_DIR/openal-soft-1.15.1" - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 install - - popd - -} - diff --git a/mingw_setup/OpenAL/install.sh b/mingw_setup/OpenAL/install.sh deleted file mode 100644 index f4f2232e6a0..00000000000 --- a/mingw_setup/OpenAL/install.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/openAl - -REMOTE_DIR="http://kcat.strangesoft.net/openal-releases" - -ARCHIVE="openal-soft-1.15.1.tar.bz2" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "OpenAL archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading OpenAL" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading OGRE archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the sources -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack OpenAL If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -# untar the sources again -ARCHIVE="openal-soft-1.15.1.tar" -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack OpenAL If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -mkdir -p $WORKING_DIR/build -cd $WORKING_DIR/build -cmake \ - -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE \ - -DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install\ - $WORKING_DIR/openal-soft-1.15.1 -make -j4 && make install - - diff --git a/mingw_setup/TinyXML/CMakeLists.txt b/mingw_setup/TinyXML/CMakeLists.txt deleted file mode 100644 index 9b22a5ba489..00000000000 --- a/mingw_setup/TinyXML/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -# TinyXML CMake build file -cmake_minimum_required(VERSION 2.6) -project(TinyXML) -set(TinyXML_SRC_DIR - "${CMAKE_CURRENT_SOURCE_DIR}/tinyxml" - CACHE STRING "Path to unpacked tinyxml source archive" -) -string(REGEX REPLACE "\\\\" "/" TinyXML_SRC_DIR "${TinyXML_SRC_DIR}") - -set(TinyXML_HEADER_FILES - ${TinyXML_SRC_DIR}/tinyxml.h - ${TinyXML_SRC_DIR}/tinystr.h -) - -set(TinyXML_SRC_FILES - ${TinyXML_SRC_DIR}/tinyxml.cpp - ${TinyXML_SRC_DIR}/tinystr.cpp - ${TinyXML_SRC_DIR}/tinyxmlparser.cpp - ${TinyXML_SRC_DIR}/tinyxmlerror.cpp -) - -include_directories(${TinyXML_SRC_DIR}/include) - -add_library(tinyxml STATIC ${TinyXML_SRC_FILES} ${TinyXML_HEADER_FILES}) - -install(TARGETS tinyxml - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib -) - -install(FILES ${TinyXML_HEADER_FILES} - DESTINATION include/tinyxml -) diff --git a/mingw_setup/TinyXML/TODO-ADD-SH b/mingw_setup/TinyXML/TODO-ADD-SH deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/mingw_setup/TinyXML/install.ps1 b/mingw_setup/TinyXML/install.ps1 deleted file mode 100644 index af901c3e162..00000000000 --- a/mingw_setup/TinyXML/install.ps1 +++ /dev/null @@ -1,141 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######### -# TinyXML2 # -######### - -Write-Output "--- Installing TinyXML2 ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\TinyXML - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="http://downloads.sourceforge.net/project/tinyxml/tinyxml/2.6.2" - -$LIB_NAME = "tinyxml_2_6_2" - -$ARCHIVE= $LIB_NAME + ".tar.gz" - -Write-Output $ARCHIVE - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.Credentials = New-Object System.Net.NetworkCredential 'thrivebuildsystem', 'autoevo1' - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$DESTINATION = (Join-Path $WORKING_DIR $LIB_NAME) + ".tar.gz" - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$DESTINATION = (Join-Path $WORKING_DIR $LIB_NAME) + ".tar" - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -$BUILD_TYPES = @("Debug", "Release") - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR - - $SRC_DIR = Join-Path $WORKING_DIR "tinyxml" - - #find the location where the script is run from (for custom cmakelists.txt) - $PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition - - - $ARGUMENTS = - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", - "-DTinyXML_SRC_DIR=$SRC_DIR", - "$PSScriptRoot" - - - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 install - - - - popd - -} - -#Copy-Item "" -destination (Join-Path $MINGW_ENV install) -Recurse -Force - diff --git a/mingw_setup/boost/install.ps1 b/mingw_setup/boost/install.ps1 deleted file mode 100644 index d684ca43487..00000000000 --- a/mingw_setup/boost/install.ps1 +++ /dev/null @@ -1,136 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######### -# Boost # -######### - -Write-Output "--- Installing Boost Libraries ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\boost - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="http://downloads.sourceforge.net/project/boost/boost/1.63.0" - -$ARCHIVE="boost_1_63_0.7z" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -############################################# -# Create user config for boost build system # -############################################# - -$MINGW_BIN_DIR = (Join-Path $MINGW_ENV bin).replace("\", "\\") - -$USER_CONFIG = " -using gcc : 5.4 : $MINGW_BIN_DIR\\g++.exe - : - $MINGW_BIN_DIR\\windres.exe - $MINGW_BIN_DIR\\ar.exe -; -" - -$USER_CONFIG_FILE = Join-Path $WORKING_DIR "user-config.jam" - -Set-Content $USER_CONFIG_FILE $USER_CONFIG - - -######### -# Build # -######### - -pushd (Join-Path $WORKING_DIR "boost_1_63_0\tools\build") - -Write-Output "Running bootstrap to generate build tool b2..." -& .\bootstrap.bat - - -Write-Output "Building boost.build..." -& .\b2 install --prefix=$WORKING_DIR\boostbuild - -Write-Output "Building libraries..." - -$ARGUMENTS = - "address-model=32", - "toolset=gcc" , - "target-os=windows", - "variant=release", - "threading=multi", - "threadapi=win32", - "link=shared", - "runtime-link=shared", - "--prefix=$MINGW_ENV/install", - "--user-config=$WORKING_DIR/user-config.jam", - "--without-mpi", - "--without-python", - "-sNO_BZIP2=1", - "-sNO_ZLIB=1", - "--layout=tagged", - "install" - -& .\b2 $ARGUMENTS - -Write-Output "Copying header files..." - -#I desperately tried using Copy-Item to copy header files but every attempt always failed to copy everything so I'm calling an xcopy -$cmd = "xcopy `$WORKING_DIR\boost_1_63_0\boost\*` `$MINGW_ENV\install\include\boost\*` /s/h/e/k/f/c" -$cmd = $ExecutionContext.InvokeCommand.ExpandString($cmd) -cmd.exe /c $cmd - -popd diff --git a/mingw_setup/boost/install.sh b/mingw_setup/boost/install.sh deleted file mode 100755 index 5741406e0a0..00000000000 --- a/mingw_setup/boost/install.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/boost - -REMOTE_DIR="http://downloads.sourceforge.net/project/boost/boost/1.53.0" - -ARCHIVE="boost_1_53_0.tar.gz" - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Boost archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading Boost" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading Boost archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the boost sources -tar -x --directory=$WORKING_DIR -f $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack boost. If the archive is corrupted, delete \n \ - \n \ - \t $WORKING_DIR/$ARCHIVE \n \ - \n \ - to force a new download. - " -fi - -cd $WORKING_DIR/boost_1_53_0/ - -# build the bjam program provided with Boost -./bootstrap.sh --without-icu - -echo "using gcc : 4.7 : $MINGW_ENV/bin/i686-w64-mingw32-g++ - : - $MINGW_ENV/bin/i686-w64-mingw32-windres - $MINGW_ENV/bin/i686-w64-mingw32-ar -;" > $WORKING_DIR/user-config.jam - -# build boost -./bjam \ - address-model=32 \ - toolset=gcc \ - target-os=windows \ - variant=release \ - threading=multi \ - threadapi=win32\ - link=shared \ - runtime-link=shared \ - --prefix=$MINGW_ENV/install \ - --user-config=$WORKING_DIR/user-config.jam \ - -j 2 \ - --without-mpi \ - --without-python \ - -sNO_BZIP2=1 \ - -sNO_ZLIB=1 \ - --layout=tagged \ - install - -cd - diff --git a/mingw_setup/bullet/install.ps1 b/mingw_setup/bullet/install.ps1 deleted file mode 100644 index 56dfd92ac23..00000000000 --- a/mingw_setup/bullet/install.ps1 +++ /dev/null @@ -1,123 +0,0 @@ -param( - [string]$MINGW_ENV -) - -########## -# Bullet # -########## - -Write-Output "--- Installing Bullet ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\bullet - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - - -$REMOTE_DIR="https://github.com/bulletphysics/bullet3/archive/" - -$LIB_NAME="619cfa2f15" -$EXTRACTED_NAME = "bullet3-619cfa2f1542d33bcd83e204ccc3747f5ec24f0a" -$ARCHIVE=$LIB_NAME + ".zip" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - - - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -#Release causes this gcc bug:https://github.com/bulletphysics/bullet3/issues/312 http://sourceforge.net/p/tdm-gcc/bugs/232/ -#$BUILD_TYPES = @("Release", "Debug") -$BUILD_TYPES = @("Debug") - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR - - $ARGUMENTS = - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", - "-DBUILD_MULTITHREADING=ON", - "-DBUILD_CPU_DEMOS=OFF", - "-DBUILD_DEMOS=OFF", - "-DBUILD_EXTRAS=OFF", - "-DUSE_GLUT=OFF", - "-DCMAKE_CXX_FLAGS:string=-msse2", - "-DINSTALL_LIBS=ON", - "$WORKING_DIR/$EXTRACTED_NAME" - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 install - - popd - -} - - diff --git a/mingw_setup/bullet/install.sh b/mingw_setup/bullet/install.sh deleted file mode 100755 index 04eb48d3fbb..00000000000 --- a/mingw_setup/bullet/install.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/bullet - -REMOTE_DIR="https://bullet.googlecode.com/files" - -ARCHIVE="bullet-2.81-rev2613.zip" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Bullet archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading Bullet" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading Bullet archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the sources -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack Bullet If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -mkdir -p $WORKING_DIR/build -cd $WORKING_DIR/build -cmake \ - -DCMAKE_TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install \ - -DBUILD_CPU_DEMOS=OFF \ - -DBUILD_DEMOS=OFF \ - -DBUILD_EXTRAS=OFF \ - -DUSE_GLUT=OFF \ - -DINSTALL_LIBS=ON \ - $WORKING_DIR/bullet-2.81-rev2613 -make -j4 && make install - - diff --git a/mingw_setup/cAudio/install.ps1 b/mingw_setup/cAudio/install.ps1 deleted file mode 100644 index 0c576e7abaa..00000000000 --- a/mingw_setup/cAudio/install.ps1 +++ /dev/null @@ -1,141 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######### -# cAudio # -######### - -Write-Output "--- Installing cAudio ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\cAudio - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - - -$REMOTE_DIR="https://github.com/R4stl1n/cAudio/archive" - -$LIB_NAME="5c932101891e4e63b93b03803d34342fbdb9f0a3" - -$ARCHIVE=$LIB_NAME + ".zip" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -(Get-Content $WORKING_DIR/cAudio-5c932101891e4e63b93b03803d34342fbdb9f0a3/cAudio/include/cAudioString.h) | -Foreach-Object {$_ -replace '1023, 0, false',' 1023, 0, (int)false'} | -Out-File -Encoding "UTF8" $WORKING_DIR/cAudio-5c932101891e4e63b93b03803d34342fbdb9f0a3/cAudio/include/cAudioString.h - - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -#Debug fails to build if it's built first. -#Was unable to figure out why, but doing release first works -$BUILD_TYPES = @("Release", "Debug") - - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - #Fetch the dependencies - $DEPS_LOC = "$MINGW_ENV/temp/cAudio-5c932101891e4e63b93b03803d34342fbdb9f0a3/Dependencies" - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR - - $LIB_SRC = Join-Path $WORKING_DIR "cAudio-5c932101891e4e63b93b03803d34342fbdb9f0a3" - - $ARGUMENTS = - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", - "-DCAUDIO_DEPENDENCIES_DIR:path=$MINGW_ENV/temp/cAudio/cAudio-5c932101891e4e63b93b03803d34342fbdb9f0a3/Dependencies", - "$LIB_SRC" - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "CodeBlocks - MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 install - - #DLL's don' seem to be copied automatically - $INSTALL_TARGET = Join-Path $MINGW_ENV "install/bin/OpenAL32.dll" - $OPENAL_DLL = Join-Path $BUILD_DIR "bin/OpenAL32.dll" - Copy-Item $OPENAL_DLL -destination $INSTALL_TARGET -Recurse -Force - $INSTALL_TARGET = Join-Path $MINGW_ENV "install/bin/wrap_oal.dll" - $WRAPOAL_DLL = Join-Path $BUILD_DIR "bin/wrap_oal.dll" - Copy-Item $WRAPOAL_DLL -destination $INSTALL_TARGET -Recurse -Force - - - popd - -} -#DLL's don' seem to be copied automatically -$INSTALL_TARGET = Join-Path $MINGW_ENV "install/bin/libcAudio.dll" -$CAUDIO_DLL = Join-Path $WORKING_DIR "build-Release/bin/release/libcAudio.dll" -Copy-Item $CAUDIO_DLL -destination $INSTALL_TARGET -Recurse -Force -$INSTALL_TARGET = Join-Path $MINGW_ENV "install/bin/libcAudio_d.dll" -$CAUDIO_DLL = Join-Path $WORKING_DIR "build-Debug/bin/debug/libcAudio_d.dll" -Copy-Item $CAUDIO_DLL -destination $INSTALL_TARGET -Recurse -Force \ No newline at end of file diff --git a/mingw_setup/cegui/install.ps1 b/mingw_setup/cegui/install.ps1 deleted file mode 100644 index b5933783c98..00000000000 --- a/mingw_setup/cegui/install.ps1 +++ /dev/null @@ -1,150 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######### -# CEGUI # -######### - -Write-Output "--- Installing CEGUI ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\cegui - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="https://bitbucket.org/cegui/cegui/get" -$LIB_NAME="869014de5669" -$EXTRACTED_NAME = "cegui-cegui-869014de5669" - -$ARCHIVE=$LIB_NAME + ".zip" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -#Debug fails to build if it's built first. -#Was unable to figure out why, but doing release first works -$BUILD_TYPES = @("Release", "Debug") - - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - #Fetch the dependencies - $DEPS_LOC = "$MINGW_ENV/temp/cegui_deps/build-" + $BUILD_TYPE + "/dependencies" - $DEPS_TARGET = "$WORKING_DIR/" + $EXTRACTED_NAME - Copy-Item $DEPS_LOC -destination $DEPS_TARGET -Recurse -Force - - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR - - $LIB_SRC = Join-Path $WORKING_DIR $EXTRACTED_NAME - - $MINGW_ENV = $MINGW_ENV -replace "\\", "/" - - # hacky way to add tinyxml dependency, the cegui_deps didn't seem to build it correctly so we do it manually - $ARGUMENTS = - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", - "-DOGRE_HOME:path=$MINGW_ENV/OgreSDK", - "-DCEGUI_BUILD_XMLPARSER_TINYXML:bool=TRUE", - "-DCEGUI_BUILD_RENDERER_OPENGL:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_OPENGL3:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_IRRLICHT:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_DIRECTFB:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_DIRECT3D9:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_DIRECT3D10:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_DIRECT3D11:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_NULL:bool=FALSE", - "-DCEGUI_BUILD_RENDERER_OGRE:bool=TRUE", - "-DCEGUI_BUILD_RENDERER_OPENGLES:bool=FALSE", - "-DCEGUI_STRING_CLASS=1", - "-DCEGUI_SAMPLES_ENABLED:bool=FALSE", - "-DCMAKE_CXX_FLAGS:string=-msse2 -std=c++0x", - "-DCEGUI_OPTION_DEFAULT_XMLPARSER:string=TinyXMLParser", - "-DCEGUI_TINYXML_HAS_2_6_API:bool=TRUE", - "-DTINYXML_H_PATH:path=$MINGW_ENV/install/include/tinyxml", - # -"DBoost_INCLUDE_DIR:path=$MINGW_ENV/install/include/boost", - "-DTINYXML_LIB_DBG:filepath=$MINGW_ENV/install/lib/libtinyxml.a", - "$LIB_SRC" - - Write-Output $MINGW_ENV/install/lib/libtinyxml.a - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "CodeBlocks - MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 install - - - popd - -} -#Debug thinks that it fails and doesn't install properly atm so we do it manually. -#Copy-Item "$MINGW_ENV/temp/cegui/build-Debug/bin/libCEGUIBase-9999_d.dll" -destination "$MINGW_ENV/install/lib/libCEGUIBase-9999_d.dll" -Recurse -Force -#Copy-Item "$MINGW_ENV/temp/cegui/build-Debug/bin/libCEGUICommonDialogs-9999_d.dll" -destination "$MINGW_ENV/install/lib/libCEGUICommonDialogs-9999_d.dll" -Recurse -Force -#Copy-Item "$MINGW_ENV/temp/cegui/build-Debug/bin/libCEGUIOgreRenderer-9999_d.dll" -destination "$MINGW_ENV/install/lib/libCEGUIOgreRenderer-9999_d.dll" -Recurse -Force \ No newline at end of file diff --git a/mingw_setup/cegui/install.sh b/mingw_setup/cegui/install.sh deleted file mode 100644 index 04eb48d3fbb..00000000000 --- a/mingw_setup/cegui/install.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/bullet - -REMOTE_DIR="https://bullet.googlecode.com/files" - -ARCHIVE="bullet-2.81-rev2613.zip" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Bullet archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading Bullet" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading Bullet archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the sources -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack Bullet If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -mkdir -p $WORKING_DIR/build -cd $WORKING_DIR/build -cmake \ - -DCMAKE_TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install \ - -DBUILD_CPU_DEMOS=OFF \ - -DBUILD_DEMOS=OFF \ - -DBUILD_EXTRAS=OFF \ - -DUSE_GLUT=OFF \ - -DINSTALL_LIBS=ON \ - $WORKING_DIR/bullet-2.81-rev2613 -make -j4 && make install - - diff --git a/mingw_setup/cegui_dependencies/install.ps1 b/mingw_setup/cegui_dependencies/install.ps1 deleted file mode 100644 index 3e12aa05b93..00000000000 --- a/mingw_setup/cegui_dependencies/install.ps1 +++ /dev/null @@ -1,133 +0,0 @@ -param( - [string]$MINGW_ENV -) - -###################### -# CEGUI Dependencies # -###################### - -Write-Output "--- Installing CEGUI Dependencies ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\cegui_deps - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - - -$REMOTE_DIR="https://bitbucket.org/cegui/cegui-dependencies/get" - -$COMMIT = "051a02c23494" -$ARCHIVE="051a02c.zip" -$EXTRACTED_NAME = "cegui-cegui-dependencies-" + $COMMIT -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -$BUILD_TYPES = @("Debug", "Release") - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR - - $ARGUMENTS = - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install/dependencies", - "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", - "-DCEGUI_BUILD_TOLUAPP:bool=false", - "-DCEGUI_BUILD_LUA:bool=false", - "-DCEGUI_BUILD_XERCES:bool=FALSE", - "-DCEGUI_BUILD_EXPAT:bool=FALSE", - "-DCEGUI_BUILD_PCRE:bool=FALSE", - "-DCEGUI_BUILD_ZLIB:bool=FALSE", - "-DCEGUI_BUILD_EFFECTS11:bool=FALSE", - "-DCEGUI_BUILD_GLEW:bool=FALSE", - "-DCEGUI_BUILD_TINYXML:bool=FALSE", - "-DCEGUI_BUILD_MINIZIP:bool=FALSE", - "-DCEGUI_BUILD_GLFW:bool=FALSE", - "-DCEGUI_BUILD_GLM:bool=TRUE", - "-DCEGUI_BUILD_FREEIMAGE:bool=TRUE", - "$WORKING_DIR/$EXTRACTED_NAME" - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 all - - $BIN_LOC = "$MINGW_ENV/temp/cegui_deps/build-" + $BUILD_TYPE + "/dependencies/bin/*" - $BIN_TARGET = "$MINGW_ENV/install/bin/" + $BUILD_TYPE - Copy-Item $BIN_LOC -destination $BIN_TARGET -Recurse -Force - - #Install GLM headers - $GLM_H = "$MINGW_ENV/temp/cegui_deps/cegui-cegui-dependencies-" + $COMMIT + "/src/glm-0.9.4.5/glm" - $GLM_H_TARGET = "$MINGW_ENV/install/include/" - Copy-Item $GLM_H -destination $GLM_H_TARGET -Recurse -Force - - - - popd - -} - - diff --git a/mingw_setup/cegui_dependencies/install.sh b/mingw_setup/cegui_dependencies/install.sh deleted file mode 100644 index 04eb48d3fbb..00000000000 --- a/mingw_setup/cegui_dependencies/install.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/bullet - -REMOTE_DIR="https://bullet.googlecode.com/files" - -ARCHIVE="bullet-2.81-rev2613.zip" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Bullet archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading Bullet" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading Bullet archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the sources -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack Bullet If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -mkdir -p $WORKING_DIR/build -cd $WORKING_DIR/build -cmake \ - -DCMAKE_TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install \ - -DBUILD_CPU_DEMOS=OFF \ - -DBUILD_DEMOS=OFF \ - -DBUILD_EXTRAS=OFF \ - -DUSE_GLUT=OFF \ - -DINSTALL_LIBS=ON \ - $WORKING_DIR/bullet-2.81-rev2613 -make -j4 && make install - - diff --git a/mingw_setup/cmake/install.ps1 b/mingw_setup/cmake/install.ps1 deleted file mode 100644 index c8414b9a329..00000000000 --- a/mingw_setup/cmake/install.ps1 +++ /dev/null @@ -1,87 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######### -# cmake # -######### - -Write-Output "--- Installing cmake ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\cmake - -mkdir $WORKING_DIR -force | out-null - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="https://cmake.org/files/v3.4/" -$ARCHIVE="cmake-3.4.1-win32-x86.zip" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -Write-Output "Unpacking archive..." - -& $7z $ARGUMENTS | out-null - -Write-Output "Installing..." - -Copy-Item (Join-Path $WORKING_DIR "cmake-3.4.1-win32-x86\*") -destination (Join-Path $MINGW_ENV cmake) -Recurse -Force - - -################################## -# Configure CMake toolchain file # -################################## - -$ESCAPED_MINGW_ENV = $MINGW_ENV.replace("\", "/") - -$ARGUMENTS = "-DTOOLCHAIN_TEMPLATE=$TOOLCHAIN_TEMPLATE", - "-DMINGW_ENV=$ESCAPED_MINGW_ENV", - "-P", - "$DIR\../configure_toolchain.cmake" - -& (Join-Path $MINGW_ENV cmake\bin\cmake) $ARGUMENTS #| out-null diff --git a/mingw_setup/cmake/install.sh b/mingw_setup/cmake/install.sh deleted file mode 100644 index 7f6703e3c93..00000000000 --- a/mingw_setup/cmake/install.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# Import utilities -. utils.sh - - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/mingw - -mkdir -p $WORKING_DIR - - -################################################################################ -# Check for necessary commands -################################################################################ -if [[ ! `commandExists tar` ]]; then - echo "No suitable command to unpack archive found. Aborting." - exit 1 -fi - -################################################################################ -# Prepare mingw-w64 -################################################################################ - -# Download mingw -REMOTE_DIR="http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win32/Personal%20Builds/rubenvb/gcc-4.7-release" -ARCHIVE="i686-w64-mingw32-gcc-4.7.4-release-linux64_rubenvb.tar.xz" - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading MinGW..." - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading mingw archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - -# Unpack mingw -tar --directory $WORKING_DIR -xf $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Error unpacking archive. Try deleting $WORKING_DIR/$ARCHIVE and redownloading." - exit 1 -fi -rsync -avh $WORKING_DIR/mingw32/* $MINGW_ENV/ - diff --git a/mingw_setup/configure_toolchain.cmake b/mingw_setup/configure_toolchain.cmake deleted file mode 100644 index c11a253080f..00000000000 --- a/mingw_setup/configure_toolchain.cmake +++ /dev/null @@ -1 +0,0 @@ -configure_file(${TOOLCHAIN_TEMPLATE} ${MINGW_ENV}/cmake/toolchain.cmake @ONLY) \ No newline at end of file diff --git a/mingw_setup/ffmpeg/install.ps1 b/mingw_setup/ffmpeg/install.ps1 deleted file mode 100644 index 0345a287a25..00000000000 --- a/mingw_setup/ffmpeg/install.ps1 +++ /dev/null @@ -1,167 +0,0 @@ -param( - [string]$MINGW_ENV -) - -########## -# FFMPEG # -########## - -Write-Output "--- Installing FFMPEG ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\ffmpeg - -mkdir $WORKING_DIR -force | out-null - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - -#################### -# Download archive # -#################### - - -#$REMOTE_DIR="https://github.com/Revolutionary-Games/ogre-ffmpeg-videoplayer/archive" -# -#$LIB_NAME="master" -# -#$ARCHIVE=$LIB_NAME + ".zip" -# -#$OGRE_FFMPEG_DESTINATION = Join-Path $WORKING_DIR $LIB_NAME -#$OGRE_FFMPEG_DESTINATION_FILE = $ARCHIVE -#if (-Not (Test-Path $OGRE_FFMPEG_DESTINATION_FILE)) { -# Write-Output "Downloading archive..." -# $CLIENT = New-Object System.Net.WebClient -# $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $OGRE_FFMPEG_DESTINATION_FILE) -#} -#else { -# Write-Output "Found archive file, skipping download." -#} - -#Download FFMPEG dependency libraries -$FFMPEG_DEV_DESTINATION = Join-Path $WORKING_DIR "ffmpeg-20161230-6993bb4-win32-dev" -$FFMPEG_DEV_DESTINATION_FILE = $FFMPEG_DEV_DESTINATION + ".zip" -if (-Not (Test-Path $FFMPEG_DEV_DESTINATION_FILE)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-20161230-6993bb4-win32-dev.zip", $FFMPEG_DEV_DESTINATION_FILE) -} -else { - Write-Output "Found archive file, skipping download." -} -#Download FFMPEG dependency binaries -$FFMPEG_BIN_DESTINATION = Join-Path $WORKING_DIR "ffmpeg-20161230-6993bb4-win32-shared" -$FFMPEG_BIN_DESTINATION_FILE = $FFMPEG_BIN_DESTINATION + ".zip" -if (-Not (Test-Path $FFMPEG_BIN_DESTINATION_FILE)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-20161230-6993bb4-win32-shared.zip", $FFMPEG_BIN_DESTINATION_FILE) -} -else { - Write-Output "Found archive file, skipping download." -} - - - - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $FFMPEG_DEV_DESTINATION_FILE - -& $7z $ARGUMENTS | out-null - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $FFMPEG_BIN_DESTINATION_FILE - -& $7z $ARGUMENTS | out-null - -########### -# Compile # -########### - -Write-Output "Compiling..." - -#$env:Path += (Join-Path $MINGW_ENV bin) + ";" -# -#$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" -# -#$BUILD_TYPES = @("Debug", "Release") -# -#foreach ($BUILD_TYPE in $BUILD_TYPES) { -# -# $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" -# -# mkdir $BUILD_DIR -force -# -# pushd $BUILD_DIR -# -# $ARGUMENTS = -# "-DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE", -# "-DOGRE_HOME:path=$MINGW_ENV/OgreSDK", -# "-DFFMPEG_LIBRARIES=$FFMPEG_DEV_DESTINATION/lib", -# "-DFFMPEG_INCLUDE_DIRS=$FFMPEG_DEV_DESTINATION/include", -# "-DAVCODEC_LIBRARIES=$FFMPEG_DEV_DESTINATION/lib", -# "-DAVCODEC_INCLUDE_DIRS=$FFMPEG_DEV_DESTINATION/include", -# "-DAVFORMAT_LIBRARIES=$FFMPEG_DEV_DESTINATION/lib", -# "-DAVFORMAT_INCLUDE_DIRS=$FFMPEG_DEV_DESTINATION/include", -# "-DAVUTIL_LIBRARIES=$FFMPEG_DEV_DESTINATION/lib", -# "-DAVUTIL_INCLUDE_DIRS=$FFMPEG_DEV_DESTINATION/include", -# "-DSWSCALE_LIBRARIES=$FFMPEG_DEV_DESTINATION/lib", -# "-DSWSCALE_INCLUDE_DIRS=$FFMPEG_DEV_DESTINATION/include", -# "-DSWRESAMPLE_LIBRARIES=$FFMPEG_DEV_DESTINATION/lib", -# "-DSWRESAMPLE_INCLUDE_DIRS=$FFMPEG_DEV_DESTINATION/include", -# "-DCMAKE_CXX_FLAGS:string=-mstackrealign -msse2", -# "-DBUILD_VIDEOPLAYER_DEMO=OFF", -# "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", -# "$WORKING_DIR/ogre-ffmpeg-videoplayer-master" -# -# & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "CodeBlocks - MinGW Makefiles" $ARGUMENTS -# -# & $MINGW_ENV/bin/mingw32-make -j4 all | Tee-Object -FilePath compileroutput.txt -# -# Copy-Item "$BUILD_DIR/libogre-ffmpeg-videoplayer.a" -destination "$MINGW_ENV/install/lib/$BUILD_TYPE/libogre-ffmpeg-videoplayer.a" -Recurse -Force -# popd -# -#} -Copy-Item "$FFMPEG_DEV_DESTINATION/lib/libavcodec.dll.a" -destination "$MINGW_ENV/install/lib/libavcodec.dll.a" -Recurse -Force -Copy-Item "$FFMPEG_DEV_DESTINATION/lib/libavformat.dll.a" -destination "$MINGW_ENV/install/lib/libavformat.dll.a" -Recurse -Force -Copy-Item "$FFMPEG_DEV_DESTINATION/lib/libavutil.dll.a" -destination "$MINGW_ENV/install/lib/libavutil.dll.a" -Recurse -Force -Copy-Item "$FFMPEG_DEV_DESTINATION/lib/libswscale.dll.a" -destination "$MINGW_ENV/install/lib/libswscale.dll.a" -Recurse -Force -Copy-Item "$FFMPEG_DEV_DESTINATION/lib/libswresample.dll.a" -destination "$MINGW_ENV/install/lib/libswresample.dll.a" -Recurse -Force -Copy-Item "$FFMPEG_BIN_DESTINATION/bin/avcodec-57.dll" -destination "$MINGW_ENV/install/bin/avcodec-57.dll" -Recurse -Force -Copy-Item "$FFMPEG_BIN_DESTINATION/bin/avformat-57.dll" -destination "$MINGW_ENV/install/bin/avformat-57.dll" -Recurse -Force -Copy-Item "$FFMPEG_BIN_DESTINATION/bin/avutil-55.dll" -destination "$MINGW_ENV/install/bin/avutil-55.dll" -Recurse -Force -Copy-Item "$FFMPEG_BIN_DESTINATION/bin/swscale-4.dll" -destination "$MINGW_ENV/install/bin/swscale-4.dll" -Recurse -Force -Copy-Item "$FFMPEG_BIN_DESTINATION/bin/swresample-2.dll" -destination "$MINGW_ENV/install/bin/swresample-2.dll" -Recurse -Force - - -Copy-Item "$FFMPEG_DEV_DESTINATION/include/*" "$MINGW_ENV/install/include/" -Recurse -Force - diff --git a/mingw_setup/gtest/install.ps1 b/mingw_setup/gtest/install.ps1 deleted file mode 100644 index 56c53d8148f..00000000000 --- a/mingw_setup/gtest/install.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -param( - [string]$MINGW_ENV -) - -############### -# Google Test # -############### - -Write-Output "--- Installing Google Test Library ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\gtest - -mkdir $WORKING_DIR -force | out-null - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="http://googletest.googlecode.com/files" - -$ARCHIVE="gtest-1.6.0.zip" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -Unzip $DESTINATION $WORKING_DIR - - -Copy-Item (Join-Path $WORKING_DIR "gtest-1.6.0") -destination (Join-Path $MINGW_ENV "gtest") -Recurse -Force diff --git a/mingw_setup/gtest/install.sh b/mingw_setup/gtest/install.sh deleted file mode 100755 index 8d4fb36637b..00000000000 --- a/mingw_setup/gtest/install.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/gtest - -REMOTE_DIR="http://googletest.googlecode.com/files" - -ARCHIVE="gtest-1.6.0.zip" - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Google Test archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading Google Test" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading Google Test archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, install -################################################################################ - -# untar the sources -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack Google Test. If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -rsync -avh $WORKING_DIR/gtest-1.6.0/* $MINGW_ENV/gtest - diff --git a/mingw_setup/lua51.dll b/mingw_setup/lua51.dll deleted file mode 100644 index 729eb3b1ac14832e7a0eda9eab9f08b0ae01345c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 456783 zcmd?Sdtg-6wLd%Fz*_H}C`;470rCPcvmR1z?}R6N5044`Cyz=?^~e#1l^{>EC-ey&~{L`hq9Yi|#5*fBeaZ9v*ecC4+qy z=+a`FZL)o^&2~Rt=&80!{Ml5s-=}O!96r1g%RGSU|cezpE!hiSUoh@1}o|8)DmG|?}cE!}KK4X8c-i9bE5w*Pk0w=~-!p#Q>u*=e?ntG}?+CZ(s@ zJQpc;B&FHb5n*5OZ@%QcX>t*MS`d%dsg)M_< z+KU0W$iEufqQ+4Vn|K8;!Bg8%RQ%hy^+8|Ws0C&{lh+s{;{9tE)N347c=vQdl|>&e z)T92kUZkF~P|%l7^)LpaUfV_LRXn`#$p_I78bgew&5OTpUr?`r!2JL5UzvKy6PA26 z=)0a?lwxDeO!DasIVrZ_u0J|II$Qon2R@Wb!lWc@>PAmaK>PFYx`S&$BZR~{h+Kni(si*9sB=FHg zFVH;9Il*U1{0>5DTmgLkPPx_zJaN1`fS2_E

Mq?wnl~QoCGxEozEy=tJ#Mfa@>1 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%0DW9AiY7o-zBRH8!pdg(NV6s{vDlmNT~ILtPuCFr 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

Lm{|T~WXtLmZ^4== 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

W4hoQvgK!aH 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%0D&&t5j5HZYfqpZLp6U$e>Rd1K5*@^?fs>{ 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 aGj=K6!=50_BV#G^`fTR|lWE&$mi`M1H5+;W diff --git a/mingw_setup/luajit.exe b/mingw_setup/luajit.exe deleted file mode 100644 index 45ad402d53c592b5b787551d3fbb95a157042fd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28090 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%0A3Xw^Jf4BB;YYgx`x5cNBO+BG^#WFkoMhih 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 diff --git a/mingw_setup/luajit/install.ps1 b/mingw_setup/luajit/install.ps1 deleted file mode 100644 index fb836c8f132..00000000000 --- a/mingw_setup/luajit/install.ps1 +++ /dev/null @@ -1,50 +0,0 @@ -param( - [string]$MINGW_ENV -) - -########## -# FFMPEG # -########## - -Write-Output "--- Installing luajit ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - -############################ -# Create working directory # -############################ - -$WORKING_DIR = "$DIR\..\..\contrib\lua\luajit" - -mkdir $WORKING_DIR -force | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - - - - - - -#$BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" -pushd $WORKING_DIR - -$env:Path += ";${MINGW_ENV}/bin" - - - -& $MINGW_ENV/bin/mingw32-make -j4 all | Tee-Object -FilePath compileroutput.txt -popd - - - diff --git a/mingw_setup/mingw/install.ps1 b/mingw_setup/mingw/install.ps1 deleted file mode 100644 index 9d03d6e10cf..00000000000 --- a/mingw_setup/mingw/install.ps1 +++ /dev/null @@ -1,84 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######### -# MinGW # -######### - -Write-Output "--- Installing MinGW ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\mingw - -mkdir $WORKING_DIR -force | out-null - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -##$REMOTE_DIR="https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/4.9.3/threads-win32/dwarf/" -##$ARCHIVE="i686-4.9.3-release-win32-dwarf-rt_v4-rev1.7z" -$REMOTE_DIR="https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/5.4.0/threads-win32/dwarf/" -$ARCHIVE="i686-5.4.0-release-win32-dwarf-rt_v5-rev0.7z" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -Write-Output "Unpacking archive..." - -& $7z $ARGUMENTS | out-null - -Write-Output "Installing..." -Copy-Item (Join-Path $WORKING_DIR "mingw32\*") -destination $MINGW_ENV -Recurse -Force -if(!(Test-Path -Path "C:\mingw\bin" )){ - New-Item "C:\mingw\bin" -type directory - New-Item "C:\mingw\i686-w64-mingw32" -type directory - New-Item "C:\mingw\lib" -type directory - New-Item "C:\mingw\libexec" -type directory -} -Copy-Item (Join-Path $WORKING_DIR "mingw32\bin\*") -destination "C:\mingw\bin" -Recurse -Force -Copy-Item (Join-Path $WORKING_DIR "mingw32\i686-w64-mingw32\*") -destination "C:\mingw\i686-w64-mingw32" -Recurse -Force -Copy-Item (Join-Path $WORKING_DIR "mingw32\lib\*") -destination "C:\mingw\lib" -Recurse -Force -Copy-Item (Join-Path $WORKING_DIR "mingw32\libexec\*") -destination "C:\mingw\libexec" -Recurse -Force diff --git a/mingw_setup/mingw/install.sh b/mingw_setup/mingw/install.sh deleted file mode 100755 index 7f6703e3c93..00000000000 --- a/mingw_setup/mingw/install.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# Import utilities -. utils.sh - - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/mingw - -mkdir -p $WORKING_DIR - - -################################################################################ -# Check for necessary commands -################################################################################ -if [[ ! `commandExists tar` ]]; then - echo "No suitable command to unpack archive found. Aborting." - exit 1 -fi - -################################################################################ -# Prepare mingw-w64 -################################################################################ - -# Download mingw -REMOTE_DIR="http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win32/Personal%20Builds/rubenvb/gcc-4.7-release" -ARCHIVE="i686-w64-mingw32-gcc-4.7.4-release-linux64_rubenvb.tar.xz" - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading MinGW..." - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading mingw archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - -# Unpack mingw -tar --directory $WORKING_DIR -xf $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Error unpacking archive. Try deleting $WORKING_DIR/$ARCHIVE and redownloading." - exit 1 -fi -rsync -avh $WORKING_DIR/mingw32/* $MINGW_ENV/ - diff --git a/mingw_setup/ogg/CMakeLists.txt b/mingw_setup/ogg/CMakeLists.txt deleted file mode 100644 index 93771784b57..00000000000 --- a/mingw_setup/ogg/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -# OGG CMake build file -cmake_minimum_required(VERSION 2.6) -project(OGG) -set(OGG_SRC_DIR - "${CMAKE_CURRENT_SOURCE_DIR}/libogg-1.3.1" - CACHE STRING "Path to unpacked libogg source archive" -) -string(REGEX REPLACE "\\\\" "/" OGG_SRC_DIR "${OGG_SRC_DIR}") - -message(${OGG_SRC_DIR}) -set(OGG_HEADER_FILES - ${OGG_SRC_DIR}/include/ogg/ogg.h - ${OGG_SRC_DIR}/include/ogg/os_types.h -) - -set(OGG_SRC_FILES - ${OGG_SRC_DIR}/src/bitwise.c - ${OGG_SRC_DIR}/src/framing.c - ${OGG_SRC_DIR}/win32/ogg.def -) - -include_directories(${OGG_SRC_DIR}/include) - -add_library(ogg STATIC ${OGG_SRC_FILES} ${OGG_HEADER_FILES}) - -install(TARGETS ogg - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib -) - -install(FILES ${OGG_HEADER_FILES} - DESTINATION include/ogg -) diff --git a/mingw_setup/ogg/install.ps1 b/mingw_setup/ogg/install.ps1 deleted file mode 100644 index 992827254b1..00000000000 --- a/mingw_setup/ogg/install.ps1 +++ /dev/null @@ -1,117 +0,0 @@ -param( - [string]$MINGW_ENV -) - -########## -# OGG # -########## - -Write-Output "--- Installing OGG ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\OGG - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="http://downloads.xiph.org/releases/ogg" - -$ARCHIVE="libogg-1.3.1.tar.gz" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - - -########## -# Unpack # -########## - -#unpack tar.gz to .tar -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS - -#unpack .tar -$DESTINATION = Join-Path $WORKING_DIR "libogg-1.3.1.tar" - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -mkdir "$WORKING_DIR/build" -force -pushd "$WORKING_DIR/build" - -#find the location where the script is run from (for custom cmakelists.txt) -$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition - -$ARGUMENTS = - "-DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE", - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "-DOGG_SRC_DIR=$WORKING_DIR/libogg-1.3.1", - "$PSScriptRoot" - -& (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - -& $MINGW_ENV/bin/mingw32-make -j4 install - -popd - - diff --git a/mingw_setup/ogg/install.sh b/mingw_setup/ogg/install.sh deleted file mode 100755 index 347a32c97fa..00000000000 --- a/mingw_setup/ogg/install.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/ogg - -REMOTE_DIR="http://downloads.xiph.org/releases/ogg" - -ARCHIVE="libogg-1.3.1.tar.gz" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -DIR=`getScriptDirectory` - -CMAKE_LISTS=$DIR/CMakeLists.txt - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Ogg archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading Ogg" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading Ogg archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the sources -tar --directory $WORKING_DIR -xf $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack Ogg. If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -mkdir -p $WORKING_DIR/build -cd $WORKING_DIR/build -cmake \ - -DCMAKE_TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install \ - -DOGG_SRC_DIR=$WORKING_DIR/libogg-1.3.1 \ - $DIR -make -j4 && make install - - diff --git a/mingw_setup/ogre/install.ps1 b/mingw_setup/ogre/install.ps1 deleted file mode 100644 index d8dc63e743a..00000000000 --- a/mingw_setup/ogre/install.ps1 +++ /dev/null @@ -1,131 +0,0 @@ -param( - [string]$MINGW_ENV -) - -######## -# Ogre # -######## - -Write-Output "--- Installing Ogre SDK ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\ogre - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - - -$REPOSITORY_NAME="sinbad" - -$REMOTE_DIR="https://bitbucket.org/sinbad/ogre/get" - - -$COMMIT_ID="b6eeaf8a7c5d" - -$ARCHIVE="$COMMIT_ID.zip" - -$ARCHIVE_TOP_LEVEL_DIR="$REPOSITORY_NAME-ogre-$COMMIT_ID" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - - - - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -#& $7z $ARGUMENTS | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -$BUILD_TYPES = @("Debug", "Release") - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR -#-mstackrealign is needed as sse2 assumes stack is aligned but gcc doesn't allign stack by default. -#this flag can cause some performance issues in which case alternative solutions are possible -#See http://www.peterstock.co.uk/games/mingw_sse/ - $ARGUMENTS = - "-DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE", - "-DOGRE_DEPENDENCIES_DIR=$MINGW_ENV/install", - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/OgreSDK", - "-DOGRE_THREAD_PROVIDER=1", - "-DOGRE_CONFIG_THREADS=1", - "-DOGRE_USE_BOOST=ON", - "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", - "-DOGRE_BUILD_RENDERSYSTEM_D3D9=OFF", - "-DOGRE_BUILD_RENDERSYSTEM_D3D11=OFF", - "-DOGRE_BUILD_SAMPLES=OFF", - "-DOGRE_BUILD_TOOLS=OFF", - "-DCMAKE_CXX_FLAGS:string=-mstackrealign -std=c++1y", - "-DDirectX_DXERR_LIBRARY=$MINGW_ENV/x86_64-mingw32/lib/libdxerr9.a", - "$WORKING_DIR/sinbad-ogre-$COMMIT_ID" - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 install | Tee-Object -FilePath compileroutput.txt - - popd - -} - - diff --git a/mingw_setup/ogre/install.sh b/mingw_setup/ogre/install.sh deleted file mode 100755 index 6f69161879b..00000000000 --- a/mingw_setup/ogre/install.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -BUILD_TYPES=("Debug" "Release") - -WORKING_DIR=$MINGW_ENV/temp/ogre - -REMOTE_DIR="http://downloads.sourceforge.net/project/ogre/ogre/1.8/1.8.1" - -ARCHIVE="ogre_src_v1-8-1.exe" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -OGRE_SRC_DIR=$WORKING_DIR/ogre_src_v1-8-1 - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "OGRE archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading OGRE" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading OGRE archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the sources -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack OGRE If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -for BUILD_TYPE in ${BUILD_TYPES[@]} -do - BUILD_DIR=$WORKING_DIR/build-$BUILD_TYPE - mkdir -p $BUILD_DIR - cd $BUILD_DIR - cmake \ - -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE \ - -DOGRE_DEPENDENCIES_DIR=$MINGW_ENV/install \ - -DCMAKE_INSTALL_PREFIX=$MINGW_ENV/OgreSDK \ - -DOGRE_CONFIG_THREADS=1 \ - -DOGRE_USE_BOOST=ON \ - -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ - -DOGRE_BUILD_RENDERSYSTEM_D3D9=OFF \ - -DDirectX_DXERR_LIBRARY=$MINGW_ENV/x86_64-mingw32/lib/libdxerr9.a \ - $OGRE_SRC_DIR - make -j4 && make install - - # Fix case sensitive directory names - rsync -a $MINGW_ENV/OgreSDK/lib/$BUILD_TYPE/* $MINGW_ENV/OgreSDK/lib/`echo ${BUILD_TYPE,,}` - rsync -a $MINGW_ENV/OgreSDK/bin/$BUILD_TYPE/* $MINGW_ENV/OgreSDK/bin/`echo ${BUILD_TYPE,,}` -done - diff --git a/mingw_setup/ogre_dependencies/install.ps1 b/mingw_setup/ogre_dependencies/install.ps1 deleted file mode 100644 index 8aba6a51530..00000000000 --- a/mingw_setup/ogre_dependencies/install.ps1 +++ /dev/null @@ -1,117 +0,0 @@ -param( - [string]$MINGW_ENV -) - -##################### -# Ogre Dependencies # -##################### - -Write-Output "--- Installing Ogre Dependencies ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\ogre_dependencies - -mkdir $WORKING_DIR -force | out-null - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REPOSITORY_NAME="ali1234" - -$REMOTE_DIR="https://bitbucket.org/$REPOSITORY_NAME/ogredeps/get" - -$COMMIT_ID="4e9b0c98f4c3" - -$ARCHIVE="$COMMIT_ID.zip" - -$ARCHIVE_TOP_LEVEL_DIR="$REPOSITORY_NAME-ogredeps-$COMMIT_ID" - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -$BUILD_TYPES = @("Debug", "Release") - -foreach ($BUILD_TYPE in $BUILD_TYPES) { - - $BUILD_DIR = Join-Path $WORKING_DIR "build-$BUILD_TYPE" - - mkdir $BUILD_DIR -force - - pushd $BUILD_DIR - - $ARGUMENTS = - "-DCMAKE_PROGRAM_PATH=$MINGW_ENV/bin/", - "-DCMAKE_CXX_FLAGS:string=-Wno-narrowing", - "-DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE", - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "-DCMAKE_C_FLAGS=-shared-libgcc", - "-DCMAKE_BUILD_TYPE=$BUILD_TYPE", - "-DOGRE_COPY_DEPENDENCIES=OFF", - "$WORKING_DIR/$ARCHIVE_TOP_LEVEL_DIR" - - & (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - - & $MINGW_ENV/bin/mingw32-make -j4 install - - popd - -} - - diff --git a/mingw_setup/ogre_dependencies/install.sh b/mingw_setup/ogre_dependencies/install.sh deleted file mode 100755 index 200488c813e..00000000000 --- a/mingw_setup/ogre_dependencies/install.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/ogre_dependencies - -BUILD_TYPES=("Debug" "Release") - -REPOSITORY_NAME="ali1234" - -REMOTE_DIR="https://bitbucket.org/${REPOSITORY_NAME}/ogredeps/get" - -COMMIT_ID="4e9b0c98f4c3" - -ARCHIVE="${COMMIT_ID}.zip" - -ARCHIVE_TOP_LEVEL_DIR="${REPOSITORY_NAME}-ogredeps-${COMMIT_ID}" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "OGRE dependencies archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading OGRE dependencies" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading OGRE dependencies archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# unzip the sources -7za x -y -o$WORKING_DIR $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack OGRE dependencies. If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -# Fix case sensitive cmake module path -rsync -a $WORKING_DIR/$ARCHIVE_TOP_LEVEL_DIR/cmake/* $WORKING_DIR/$ARCHIVE_TOP_LEVEL_DIR/CMake - -for BUILD_TYPE in ${BUILD_TYPES[@]} -do - BUILD_DIR=$WORKING_DIR/build-$BUILD_TYPE - # Compile - mkdir -p $BUILD_DIR - cd $BUILD_DIR - cmake \ - -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE \ - -DCMAKE_INSTALL_PREFIX=${MINGW_ENV}/install \ - -DCMAKE_C_FLAGS=-shared-libgcc \ - -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ - -DOGRE_COPY_DEPENDENCIES=OFF \ - $WORKING_DIR/$ARCHIVE_TOP_LEVEL_DIR - make -j4 && make install - - # Fix case sensitive paths for Ogre's FindXYZ scripts - rsync -a $MINGW_ENV/install/lib/$BUILD_TYPE/* $MINGW_ENV/install/lib/`echo ${BUILD_TYPE,,}` - rsync -a $MINGW_ENV/install/bin/$BUILD_TYPE/* $MINGW_ENV/install/bin/`echo ${BUILD_TYPE,,}` - - # For some reason, OIS.dll is installed into bin, move it to lib - rsync -a $MINGW_ENV/install/bin/`echo ${BUILD_TYPE,,}`/OIS* $MINGW_ENV/install/lib/`echo ${BUILD_TYPE,,}` - - # OGRE's cmake script looks for freeimage, not FreeImage (*sigh*) - case "$BUILD_TYPE" in - "Debug") rsync -a $MINGW_ENV/install/lib/debug/libFreeImage_d.a $MINGW_ENV/install/lib/debug/libfreeimage_d.a - ;; - "Release") rsync -a $MINGW_ENV/install/lib/release/libFreeImage.a $MINGW_ENV/install/lib/release/libfreeimage.a - ;; - esac -done diff --git a/mingw_setup/readme.txt b/mingw_setup/readme.txt deleted file mode 100644 index 88e14e1a181..00000000000 --- a/mingw_setup/readme.txt +++ /dev/null @@ -1,273 +0,0 @@ -What's this? -============ - -In the directory of this readme, you will find some scripts that will help you setting up a -system for building Thrive on Windows. - - -Important Note: If you run into any trouble with the setup scripts, please -post them at - http://thrivegame.forum-free.ca/t999-development-troubleshooting - -Or if you have feedback for how to make the process better: - - http://thrivegame.forum-free.ca/t1101-build-system-discussion - -Thank you! - - -Windows 7/8 + Code::Blocks -======================== - -If you would like to use an older Windows version, please refer to the "Other -Windows Platforms" section. We currently only have experience with using codeblocks -due to its good support of make-files and mingw. Other IDEs may be possible to use -but we can't currently help with setting that up. - -The setup script will install Ogre, Mingw and other required libraries. -For a full list refer to the readme in the root of the repository. - -To set up the build system follow the steps listed below. If you are not -interested in the gory details, you can ignore everything but the bullet -points. - - -0. Requirements ---------------- - -* At least 300 MB of free hard drive space on C:\ drive specifially and 3 GB free space on the drive on which you want to put the dependencies (can also be C:/) - -* About 30-60 minutes, depending on the speed of your PC and your internet - connection - - -1. Install CMake ----------------- - -* Download CMake from - - http://www.cmake.org/cmake/resources/software.html - -* Run the installer - - -2a. Downloading required libraries ----------------------------------------------- -Step 2a is optional but recommended for beginners to the project, this will require the 3 GB of dependencies to be on your C:/ drive. -If you choose step 2a, you should skip forward to step 5. after completion. - -* Download the archive found here: - - https://mega.nz/#!0YIwnTqZ!-xCCYim-AvPkJ25rGNHaiNwmHewGDAp7YYwKFCBqOmY - -* Extract to C:\mingw - -This skips the compilation of required libraries and instead downloads precompiled ones. - -Skip to step 5. - - -2b. Enabling Powershell to run the setup script ----------------------------------------------- - -Note that this and the following steps should only be performed if you skip 2a. - -* Open "Windows Powershell" as administrator by opening the start menu, - and entering "powershell" into the search line. Then right click on - "Windows Powershell" and select "Run as Administrator". - -* At the prompt that should pop up, type in - - Set-ExecutionPolicy Unrestricted - - hit enter and confirm. - -Powershell has very strict execution policies by default. Initially, you -cannot execute scripts you downloaded (such as ours) or even scripts you wrote -yourself. To change that, we have to explicitly set the execution policy to -"Unrestricted". For security reasons, only the administrator can do that. - - -3. Run the setup script ------------------------ - -* Right-click on "setup.ps1" and select "Run with Powershell" - -* In the file dialog that should pop up, select a directory of your choice. - C:\MinGW is recommended, but otherwise 300 MB will be copied to C:/MinGW regardless. - -* This will take quite a while, so be patient. When the script is complete, - a message box will inform you. - -You will also have to point Code::Blocks to your custom directory in step (7). - -4. Optional, but recommended: Reset Powershell Execution Policy ---------------------------------------------------------------- - -* If you are paranoid (or share your PC with a naive person), you can now - reset Powershell's execution policy to something more secure. Follow the - steps outline in (1), but instead of "Unrestricted", set the policy to - "Restricted" - -5. Install Code::Blocks ------------------------ - -* Download Code::Blocks from - - http://www.codeblocks.org/downloads/26 - - and install it - -If you don't install Code::Blocks, CMake won't be able to generate a project -file in the next step. - - -6. Install tortoise svn or just svn ---------------- - -* Download TortoiseSVN from - - http://tortoisesvn.net/downloads.html - - and install it - -7. Download git and tortoisegit -_______________ -Download git from here: - -https://git-scm.com/download/ - -and install it - -then Download tortoisegit from here: - -https://tortoisegit.org/download/ - -and install it - - -8.Get the project -_______________ -now right click in the place you want to put your project into for me i prefer to make folder called building thrive -(put it in the place you like)and inside it Right-click and choose git clone in URL write: - -https://github.com/Revolutionary-Games/Thrive.git - -and in Directory the place you want to put the project files in and then \new_name_for_file_here -(ex. D:\bulding thrive\Thrive) - -then click ok - -9. Get the assets ---------------- - -* If you Installed tortoise SVN - - Right click somewhere inside the folder that appeared and click SVN Checkout. - Under URL enter: http://assets.revolutionarygamesstudio.com/ - Edit the last part of Checkout directory to "/assets" instead of "/trive_assets" - Click checkout and it will prompt you for a user - For password and username simply enter 'thrive' and 'thrive' - -* If you are instead using commandline SVN - - svn co http://assets.revolutionarygamesstudio.com ./assets - -10. Invoke CMake ---------------- - -* Start the CMake GUI from your start menu - -* Set the source code directory to Thrive's root directory (ex.D:\bulding thrive\Thrive). That should be one - directory above where this readme is located. - -* Set the build directory to an empty directory where you want to put the - compiled binaries. I like to use a "build" subdirectory of the project - -* Click on "Configure" - -* Select "CodeBlocks - MinGW Makefiles" as generator and "Specify toolchain - file for cross-compiling", then click "Next" - -* On the next page, browse to C:\MinGW\cmake\toolchain.cmake (or wherever you - installed the build environment) and click "Finish" - -* Click "Generate" to generate the Code::Blocks project files - -The toolchain file was configured during the setup script to contain paths to -the compiler executable and all accompanying tools. It's usually used for -cross-compiling, but it's convenient for us, too. - -11. Building Thrive ---------------------------- - -* Open "Thrive.cbp" in your selected build directory with Code::Blocks - -* If you didn't install to C:\MinGW, Code::Blocks will probably complain - about not being able to find the compiler. If it asks you for a default - compiler, select "Gnu GCC Compiler". Then goto "Settings -> Compiler" and - select the tab "Toolchain Executables". Point it to your installation - directory. Note that you may have to remove the mingw-32 prefix from the - default executables (EXCEPT mingw32-make). - -* If all is well, you can just click on the "Build" button (a tiny cog) to - build Thrive - - -12. Running Thrive ------------------ - -* In Code::Blocks, go to Project->Properties->Build Targets then select Install on the left and change Type: from GUI Application to -Console Application. Next, change Output Filename to "dist\bin\Thrive.exe" (without the quotes). If asks you to replace the file, -replace it. Finally, click okay and exit. - -* Select "install" as the build target and click on the - "Build and Run" button. - -* You can also go to your build/dist/bin directory and start Thrive.exe -Note that the build/Thrive.exe will not work as it is not placed with the -necessary DLL files. - - -Older Windows Platforms -======================= - -Windows versions prior to Windows 7 may not have Powershell installed by -default. You will need to find and install the appropriate Powershell version -for your system. Then the above steps should apply as well. - - -Linux - Cross Compiling for Windows -=================================== - - [ THIS FEATURE IS CURRENTLY DEPRECATED ] - It may return in the future. - -The setup.sh script takes one argument, the path to the build environment -installation directory. It defaults to /opt/mingw-w64. - -Once done, you can let CMake know about the toolchain like this: - - cmake -DCMAKE_TOOLCHAIN_FILE=/opt/mingw-w64/cmake/toolchain.cmake $SRC_DIR - - -Troubleshooting -=============== - -CMake complains about missing googletest and / or luabind ---------------------------------------------------------- -Those two dependencies are included as git submodules, which are not -automatically cloned. If you are using git from the command line, go to -the project directory and issue the commands "git submodule init", followed by -"git submodule update". - -For other clients such as TortoiseGit, look for options like -"Submodule Update" or similar. - -Building works, but when running Thrive, it complains about missing DLLs ------------------------------------------------------------------------- -Make sure to install Thrive before running it. The install target copies all -necessary files to the "dist" subdirectory in the build directory. - -For Code::Blocks, you can select the install target in a dropdown near the -build button. diff --git a/mingw_setup/setup-logged.ps1 b/mingw_setup/setup-logged.ps1 deleted file mode 100644 index 439baad1bce..00000000000 --- a/mingw_setup/setup-logged.ps1 +++ /dev/null @@ -1 +0,0 @@ -.\setup.ps1 | Tee-Object -FilePath setup-output.txt \ No newline at end of file diff --git a/mingw_setup/setup-logged.sh b/mingw_setup/setup-logged.sh deleted file mode 100644 index f3f0f5c5027..00000000000 --- a/mingw_setup/setup-logged.sh +++ /dev/null @@ -1 +0,0 @@ -sh setup.sh | tee setup-output.txt \ No newline at end of file diff --git a/mingw_setup/setup.ps1 b/mingw_setup/setup.ps1 deleted file mode 100644 index 0fc2bfde0c8..00000000000 --- a/mingw_setup/setup.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -############# -# Constants # -############# - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -$TOOLCHAIN_TEMPLATE = Join-Path $DIR toolchain_win.cmake.in - - -################# -# Include utils # -################# - -. (Join-Path $DIR utils.ps1) - - -################################## -# Ask for MinGW installation dir # -################################## - -if (Test-Path (Join-Path $DIR debugging)) { - # This is just here so you can skip the annoying file dialog - # when debugging the setup script - $MINGW_ENV = Join-Path $DIR test_win -} -else { - $MINGW_ENV = Select-Directory -Title "Select installation directory for build environment" -Directory $DIR -} - - -If ([string]::IsNullOrEmpty($MINGW_ENV)) { - exit 1 -} - -mkdir (Join-Path $MINGW_ENV cmake) -force | out-null -mkdir (Join-Path $MINGW_ENV install) -force | out-null -mkdir (Join-Path $MINGW_ENV\install bin) -force | out-null -mkdir (Join-Path $MINGW_ENV\install\bin Release) -force -mkdir (Join-Path $MINGW_ENV\install\bin Debug) -force - -##################### -# Install libraries # -##################### - -$LIBRARIES = $LIBRARIES = "7zip","cmake", "mingw", "boost", "ogre_dependencies", "ogre", "bullet", "ogg", "vorbis", "OpenAl", "TinyXML", "cegui_dependencies", "cegui","cAudio", "ffmpeg", "luajit" -foreach ($LIBRARY in $LIBRARIES) { - $INSTALL_SCRIPT = Join-Path $DIR (Join-Path $LIBRARY install.ps1) - & $INSTALL_SCRIPT $MINGW_ENV - Write-Output "`n`n`n" -} - - -################################ -# Inform user that we are done # -################################ - -$shell = new-object -comobject wscript.shell -$shell.popup("Setup script done. See readme.txt for further instructions.",0,"Thrive build setup complete",0) diff --git a/mingw_setup/setup.sh b/mingw_setup/setup.sh deleted file mode 100755 index 8c4ba5ff0fd..00000000000 --- a/mingw_setup/setup.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -. utils.sh - -################################################################################ -# Constants -################################################################################ -# The script's directory -DIR=`getScriptDirectory` - -# The toolchain template -TOOLCHAIN_TEMPLATE="$DIR/toolchain_linux.cmake.in" - -# The default root directory of the mingw environment -DEFAULT_MINGW_ENV="/opt/mingw" - -################################################################################ -# Usage -################################################################################ -USAGE="Usage: $(basename $0) [MINGW_ENV] - - MINGW_ENV is the directory to install mingw to and defaults to - $DEFAULT_MINGW_ENV - -" - -################################################################################ -# Parse arguments -################################################################################ -if [ $# -eq 0 ]; then - MINGW_ENV=$DEFAULT_MINGW_ENV -elif [ $# -eq 1 ]; then - MINGW_ENV=$1 -elif [ $# -gt 1 ]; then - echo $USAGE - exit 1 -fi - -################################################################################ -# Make paths absolute -################################################################################ -make_absolute MINGW_ENV - -################################################################################ -# Prepare directories -################################################################################ - -mkdir -p $MINGW_ENV -mkdir -p $MINGW_ENV/install -mkdir -p $MINGW_ENV/cmake - - -################################################################################ -# Configure CMake toolchain file -################################################################################ -cmake -DTOOLCHAIN_TEMPLATE=$TOOLCHAIN_TEMPLATE -DMINGW_ENV=$MINGW_ENV -P $DIR/configure_toolchain.cmake - -################################################################################ -# Install libraries -################################################################################ -LIBRARIES=('mingw' 'boost' 'ogre_dependencies' 'ogre' 'bullet' 'OpenAL') -# Not used anymore -#'irrKlang') - -for LIBRARY in ${LIBRARIES[@]} -do - $DIR/$LIBRARY/install.sh $MINGW_ENV - if [ $? -ne 0 ]; then - exit 1 - fi -done diff --git a/mingw_setup/toolchain_linux.cmake.in b/mingw_setup/toolchain_linux.cmake.in deleted file mode 100644 index c7c22a7a174..00000000000 --- a/mingw_setup/toolchain_linux.cmake.in +++ /dev/null @@ -1,51 +0,0 @@ -# the name of the target operating system -SET(CMAKE_SYSTEM_NAME Windows) - -SET(MINGW_ENV @MINGW_ENV@) - -# which compilers to use for C and C++ -SET(CMAKE_C_COMPILER ${MINGW_ENV}/bin/i686-w64-mingw32-gcc) -SET(CMAKE_CXX_COMPILER ${MINGW_ENV}/bin/i686-w64-mingw32-g++) -SET(CMAKE_RC_COMPILER ${MINGW_ENV}/bin/i686-w64-mingw32-windres) - -# here is the target environment located -SET(CMAKE_FIND_ROOT_PATH ${MINGW_ENV} ${MINGW_ENV}/install) - -# adjust the default behaviour of the FIND_XXX() commands: -# search headers and libraries in the target environment, search -# programs in the host environment -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -# Ogre -set(OGRE_SDK ${MINGW_ENV}/OgreSDK - CACHE STRING "Path to Ogre SDK" -) -list(APPEND CMAKE_MODULE_PATH - ${MINGW_ENV}/OgreSDK/CMake -) - -# DirectX SDK -set(DXSDK_DIR ${MINGW_ENV}/i686-w64-mingw32) - -# Boost -set(Boost_THREADAPI win32) - -# Add to cmake path -list(APPEND CMAKE_MODULE_PATH - ${MINGW_ENV}/cmake - ${OGRE_SDK}/CMake -) - -# Sound libraries -set(OGG_ROOT ${MINGW_ENV}/install) -set(VORBIS_ROOT ${MINGW_ENV}/install) -set(OPENAL_ROOT ${MINGW_ENV}/install) - -set(SYSTEM_DLLS - ${MINGW_ENV}/i686-w64-mingw32/lib/libgcc_s_dw2-1.dll - ${MINGW_ENV}/i686-w64-mingw32/lib/libstdc++-6.dll - ${MINGW_ENV}/i686-w64-mingw32/lib/libwinpthread-1.dll -) - diff --git a/mingw_setup/toolchain_win.cmake.in b/mingw_setup/toolchain_win.cmake.in deleted file mode 100644 index c7a426056f8..00000000000 --- a/mingw_setup/toolchain_win.cmake.in +++ /dev/null @@ -1,72 +0,0 @@ -SET(MINGW_ENV @MINGW_ENV@) - -# Set make program. Keep it in cache because some generators use -# find_program to locate a make program -SET(CMAKE_MAKE_PROGRAM ${MINGW_ENV}/bin/mingw32-make.exe - CACHE FILEPATH "Make program used for make-based generators" -) -SET(CMAKE_AR ${MINGW_ENV}/bin/ar.exe - CACHE FILEPATH "Archiver" -) - -# which compilers to use for C and C++ -SET(CMAKE_C_COMPILER ${MINGW_ENV}/bin/gcc.exe) -SET(CMAKE_CXX_COMPILER ${MINGW_ENV}/bin/g++.exe) -SET(CMAKE_RC_COMPILER ${MINGW_ENV}/bin/windres.exe) -SET(CMAKE_RANLIB ${MINGW_ENV}/bin/ranlib.exe) - -# here is the target environment located -SET(CMAKE_FIND_ROOT_PATH ${MINGW_ENV} ${MINGW_ENV}/install) - -# adjust the default behaviour of the FIND_XXX() commands: -# search headers and libraries in the target environment, search -# programs in the host environment -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - -# Ogre -set(OGRE_SDK ${MINGW_ENV}/OgreSDK - CACHE STRING "Path to Ogre SDK" -) -list(APPEND CMAKE_MODULE_PATH - ${MINGW_ENV}/OgreSDK/CMake -) - -# DirectX SDK -set(DXSDK_DIR ${MINGW_ENV}/i686-w64-mingw32) - -# Bullet -set(BULLET_ROOT ${MINGW_ENV}/install) - -# Boost -set(BOOST_ROOT ${MINGW_ENV}/install) -set(BOOST_DIR ${MINGW_ENV}/install) -set(Boost_THREADAPI win32) - -# CEGUI -set(CEGUI_ROOT ${MINGW_ENV}/install) - -# TINYXML -set(TINYXML_ROOT ${MINGW_ENV}/install) - -# CAUDIO -set(cAudio_HOME ${MINGW_ENV}/install) -set(cAudio_ROOT ${MINGW_ENV}/install) - -# Add to cmake path -list(APPEND CMAKE_MODULE_PATH - ${MINGW_ENV}/cmake - ${OGRE_SDK}/CMake -) - -# Sound libraries -set(OGG_ROOT ${MINGW_ENV}/install) -set(VORBIS_ROOT ${MINGW_ENV}/install) -set(OPENAL_ROOT ${MINGW_ENV}/install) - -set(SYSTEM_DLLS - ${MINGW_ENV}/bin/libgcc_s_dw2-1.dll - ${MINGW_ENV}/bin/libstdc++-6.dll - ${MINGW_ENV}/bin/libwinpthread-1.dll -) diff --git a/mingw_setup/utils.ps1 b/mingw_setup/utils.ps1 deleted file mode 100644 index 5f678e00326..00000000000 --- a/mingw_setup/utils.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -function Select-Directory { - param( - [string]$Title, - [string]$Directory - ) - - $app = new-object -com Shell.Application - $folder = $app.BrowseForFolder(0, $Title, 0, $ssfDRIVES) - if ($folder.Self.Path -ne "") { - return $folder.Self.Path - } - else { - return $null - } -} - - - -function Unzip { - param( - [string]$filename, - [string]$directory - ) - $shell_app=new-object -com shell.application - $archive = $shell_app.namespace($filename) - $destination = $shell_app.namespace($directory) - $destination.Copyhere($archive.items(), 0x14) -} \ No newline at end of file diff --git a/mingw_setup/utils.sh b/mingw_setup/utils.sh deleted file mode 100644 index a059eb794c5..00000000000 --- a/mingw_setup/utils.sh +++ /dev/null @@ -1,121 +0,0 @@ - - -# Checks whether a shell command is available -# Usage: -# -# commandExists $CMD -# -# Example: -# -# if [ `commandExists cd` ]; then -# echo "Found cd" -# else -# echo "cd not available" -# fi -function commandExists() -{ - local command=$1 - type -P $command -} - - -# Downloads a file with progress indicator -# Usage: -# -# download $URL [$DESTINATION_FILENAME] -# -function download() -{ - # http://fitnr.com/showing-file-download-progress-using-wget.html - local url=$1 - local destination=$2 - echo -n " " - if [ $destination ]; then - wget --progress=dot $url -O $destination 2>&1 | \ - grep --line-buffered -o "[0-9]*%" | \ - xargs -L1 echo -en "\b\b\b\b";echo - else - wget --progress=dot $url 2>&1 | \ - grep --line-buffered -o "[0-9]*%" | \ - xargs -L1 echo -en "\b\b\b\b";echo - fi - echo -ne "\b\b\b\b" - echo " DONE" -} - -# Gets the directory of the current script -# (http://stackoverflow.com/a/246128/1184818) -# -# Usage: -# -# # Note the back quotes -# DIR=`getScriptDirectory` -# -function getScriptDirectory() { - echo "$( cd "$( dirname "${BASH_SOURCE[1]}" )" && pwd )" -} - -# Converts a posix path to windows -# -# Usage: -# -# # Note the back quotes -# WIN_DIR=`posixToWinPath $POSIX_DIR` -# -function posixToWinPath() { - POSIX_PATH=$1 - echo $POSIX_PATH | sed 's/^\///' | sed 's/\//\\/g' | sed 's/^./\0:/' -} - -# Makes a path absolute -# Usage: -# -# DIR=test -# make_absolute DIR -# -function make_absolute() { - local __pathVar=$1 - eval $__pathVar=`readlink -fn ${!__pathVar}` -} - - -function runCMakeString() { - local string=$1 - cmake -P <(echo "$string") -} - -################################################################################ -# Windows or Linux? -################################################################################ -KERNEL=`uname -s` - -IS_LINUX=false -IS_WINDOWS=false - -case "$KERNEL" in - Linux) - IS_LINUX=true - ;; - *MSYS* | *NT*) - IS_WINDOWS=true - ;; -esac - -################################################################################ -# Check for 64 or 32 bit environment -################################################################################ -ARCH=`uname -m` - -case "$ARCH" in - "x86_64") - IS_64_ENV=true - ;; - "i686") - IS_64_ENV=false - ;; - *) - echo "Unknown architecture \"$ARCH\", aborting" - exit 1 - ;; -esac - diff --git a/mingw_setup/vorbis/CMakeLists.txt b/mingw_setup/vorbis/CMakeLists.txt deleted file mode 100644 index c722a3f3587..00000000000 --- a/mingw_setup/vorbis/CMakeLists.txt +++ /dev/null @@ -1,111 +0,0 @@ -# Vorbis CMake build file -cmake_minimum_required(VERSION 2.6) -project(VORBIS) - -set(VORBIS_SRC_DIR - "${CMAKE_CURRENT_SOURCE_DIR}/libvorbis-1.3.1" - CACHE STRING "Path to unpacked libvorbis source archive" -) -string(REGEX REPLACE "\\\\" "/" VORBIS_SRC_DIR "${VORBIS_SRC_DIR}") - -set(VORBIS_SRC_FILES - ${VORBIS_SRC_DIR}/lib/analysis.c - ${VORBIS_SRC_DIR}/lib/bitrate.c - ${VORBIS_SRC_DIR}/lib/block.c - ${VORBIS_SRC_DIR}/lib/codebook.c - ${VORBIS_SRC_DIR}/lib/envelope.c - ${VORBIS_SRC_DIR}/lib/floor0.c - ${VORBIS_SRC_DIR}/lib/floor1.c - ${VORBIS_SRC_DIR}/lib/info.c - ${VORBIS_SRC_DIR}/lib/lookup.c - ${VORBIS_SRC_DIR}/lib/lpc.c - ${VORBIS_SRC_DIR}/lib/lsp.c - ${VORBIS_SRC_DIR}/lib/mapping0.c - ${VORBIS_SRC_DIR}/lib/mdct.c - ${VORBIS_SRC_DIR}/lib/psy.c - ${VORBIS_SRC_DIR}/lib/registry.c - ${VORBIS_SRC_DIR}/lib/res0.c - ${VORBIS_SRC_DIR}/lib/sharedbook.c - ${VORBIS_SRC_DIR}/lib/smallft.c - ${VORBIS_SRC_DIR}/lib/synthesis.c - ${VORBIS_SRC_DIR}/win32/vorbis.def - ${VORBIS_SRC_DIR}/lib/vorbisenc.c - ${VORBIS_SRC_DIR}/lib/window.c - ${VORBIS_SRC_DIR}/lib/backends.h - ${VORBIS_SRC_DIR}/lib/bitrate.h - ${VORBIS_SRC_DIR}/lib/codebook.h - ${VORBIS_SRC_DIR}/lib/codec_internal.h - ${VORBIS_SRC_DIR}/lib/envelope.h - ${VORBIS_SRC_DIR}/lib/modes/floor_all.h - ${VORBIS_SRC_DIR}/lib/books/floor/floor_books.h - ${VORBIS_SRC_DIR}/lib/highlevel.h - ${VORBIS_SRC_DIR}/lib/lookup.h - ${VORBIS_SRC_DIR}/lib/lookup_data.h - ${VORBIS_SRC_DIR}/lib/lpc.h - ${VORBIS_SRC_DIR}/lib/lsp.h - ${VORBIS_SRC_DIR}/lib/masking.h - ${VORBIS_SRC_DIR}/lib/mdct.h - ${VORBIS_SRC_DIR}/lib/misc.h - ${VORBIS_SRC_DIR}/lib/os.h - ${VORBIS_SRC_DIR}/lib/psy.h - ${VORBIS_SRC_DIR}/lib/modes/psych_11.h - ${VORBIS_SRC_DIR}/lib/modes/psych_16.h - ${VORBIS_SRC_DIR}/lib/modes/psych_44.h - ${VORBIS_SRC_DIR}/lib/modes/psych_8.h - ${VORBIS_SRC_DIR}/lib/registry.h - ${VORBIS_SRC_DIR}/lib/books/coupled/res_books_stereo.h - ${VORBIS_SRC_DIR}/lib/books/uncoupled/res_books_uncoupled.h - ${VORBIS_SRC_DIR}/lib/modes/residue_16.h - ${VORBIS_SRC_DIR}/lib/modes/residue_44.h - ${VORBIS_SRC_DIR}/lib/modes/residue_44u.h - ${VORBIS_SRC_DIR}/lib/modes/residue_8.h - ${VORBIS_SRC_DIR}/lib/scales.h - ${VORBIS_SRC_DIR}/lib/modes/setup_11.h - ${VORBIS_SRC_DIR}/lib/modes/setup_16.h - ${VORBIS_SRC_DIR}/lib/modes/setup_22.h - ${VORBIS_SRC_DIR}/lib/modes/setup_32.h - ${VORBIS_SRC_DIR}/lib/modes/setup_44.h - ${VORBIS_SRC_DIR}/lib/modes/setup_44u.h - ${VORBIS_SRC_DIR}/lib/modes/setup_8.h - ${VORBIS_SRC_DIR}/lib/modes/setup_X.h - ${VORBIS_SRC_DIR}/lib/smallft.h - ${VORBIS_SRC_DIR}/lib/window.h -) - -set(VORBIS_HEADER_FILES - ${VORBIS_SRC_DIR}/include/vorbis/vorbisenc.h - ${VORBIS_SRC_DIR}/include/vorbis/codec.h -) - -set(VORBIS_FILE_HEADER_FILES - ${VORBIS_SRC_DIR}/include/vorbis/vorbisfile.h -) - -set(VORBIS_FILE_SRC_FILES - ${VORBIS_SRC_DIR}/lib/vorbisfile.c -) - -find_path(OGG_INCLUDE_DIR ogg/ogg.h -) - -include_directories( - ${OGG_INCLUDE_DIR} - ${VORBIS_SRC_DIR}/include - ${VORBIS_SRC_DIR}/lib -) - -add_library(vorbis STATIC ${VORBIS_SRC_FILES} ${VORBIS_HEADER_FILES}) -add_library(vorbisfile STATIC ${VORBIS_FILE_SRC_FILES} ${VORBIS_FILE_HEADER_FILES}) - -target_link_libraries(vorbis ogg) -target_link_libraries(vorbisfile vorbis) - -install(TARGETS vorbis vorbisfile - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib -) - -install(FILES ${VORBIS_HEADER_FILES} ${VORBIS_FILE_HEADER_FILES} - DESTINATION include/vorbis -) diff --git a/mingw_setup/vorbis/install.ps1 b/mingw_setup/vorbis/install.ps1 deleted file mode 100644 index 66ae541219f..00000000000 --- a/mingw_setup/vorbis/install.ps1 +++ /dev/null @@ -1,120 +0,0 @@ -param( - [string]$MINGW_ENV -) - -########## -# Vorbis # -########## - -Write-Output "--- Installing Vorbis ---" - -$DIR = Split-Path $MyInvocation.MyCommand.Path - -################# -# Include utils # -################# - -. (Join-Path "$DIR\.." "utils.ps1") - - -############################ -# Create working directory # -############################ - -$WORKING_DIR = Join-Path $MINGW_ENV temp\Vorbis - -mkdir $WORKING_DIR -force | out-null - - -################### -# Check for 7-Zip # -################### - -$7z = Join-Path $MINGW_ENV "temp\7zip\7za.exe" - -if (-Not (Get-Command $7z -errorAction SilentlyContinue)) -{ - return $false -} - - -#################### -# Download archive # -#################### - -$REMOTE_DIR="http://downloads.xiph.org/releases/vorbis" - -$ARCHIVE="libvorbis-1.3.3.tar.gz" - - -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -if (-Not (Test-Path $DESTINATION)) { - Write-Output "Downloading archive..." - $CLIENT = New-Object System.Net.WebClient - $CLIENT.DownloadFile("$REMOTE_DIR/$ARCHIVE", $DESTINATION) -} -else { - Write-Output "Found archive file, skipping download." -} - -########## -# Unpack # -########## - -#unpack .tar.gz -$DESTINATION = Join-Path $WORKING_DIR $ARCHIVE - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - -#unpack .tar -$DESTINATION = Join-Path $WORKING_DIR "libvorbis-1.3.3.tar" - -Write-Output "Unpacking archive..." - -$ARGUMENTS = "x", - "-y", - "-o$WORKING_DIR", - $DESTINATION - -& $7z $ARGUMENTS | out-null - - -########### -# Compile # -########### - -Write-Output "Compiling..." - -$env:Path += (Join-Path $MINGW_ENV bin) + ";" - -$TOOLCHAIN_FILE="$MINGW_ENV/cmake/toolchain.cmake" - -mkdir "$WORKING_DIR/build" -force - -pushd "$WORKING_DIR/build" - - -#find the location where the script is run from (for custom cmakelists.txt) -$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition - - -$ARGUMENTS = - "-DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_FILE", - "-DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install", - "-DVORBIS_SRC_DIR=$WORKING_DIR/libvorbis-1.3.3", - "$PSScriptRoot" - - -& (Join-Path $MINGW_ENV cmake\bin\cmake) -G "MinGW Makefiles" $ARGUMENTS - -& $MINGW_ENV/bin/mingw32-make -j4 install - -popd diff --git a/mingw_setup/vorbis/install.sh b/mingw_setup/vorbis/install.sh deleted file mode 100755 index 5e9e0238a0e..00000000000 --- a/mingw_setup/vorbis/install.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -. utils.sh - -MINGW_ENV=$1 - -WORKING_DIR=$MINGW_ENV/temp/vorbis - -REMOTE_DIR="http://downloads.xiph.org/releases/vorbis" - -ARCHIVE="libvorbis-1.3.3.tar.gz" - -TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake - -DIR=`getScriptDirectory` - -CMAKE_LISTS=$DIR/CMakeLists.txt - -mkdir -p $WORKING_DIR - -################################################################################ -# Download -################################################################################ - -if [ -e $WORKING_DIR/$ARCHIVE ]; then - echo "Vorbis archive file found, skipping download. If you want to redownload it, please delete ${WORKING_DIR}/${ARCHIVE}." -else - echo "Downloading Vorbis" - wget -O $WORKING_DIR/$ARCHIVE $REMOTE_DIR/$ARCHIVE - if [ $? -gt 0 ]; then - echo "Error downloading Vorbis archive. Aborting." - rm $WORKING_DIR/$ARCHIVE - exit 1 - fi -fi - - -################################################################################ -# Unpack, compile, install -################################################################################ - -# untar the sources -tar --directory $WORKING_DIR -xf $WORKING_DIR/$ARCHIVE -if [ $? -ne 0 ]; then - echo "Could not unpack Vorbis If the archive is corrupted, delete - - $WORKING_DIR/$ARCHIVE - -to force a new download. - " -fi - -mkdir -p $WORKING_DIR/build -cd $WORKING_DIR/build -cmake \ - -DCMAKE_TOOLCHAIN_FILE=$MINGW_ENV/cmake/toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=$MINGW_ENV/install \ - -DVORBIS_SRC_DIR=$WORKING_DIR/libvorbis-1.3.3 \ - $DIR -make -j4 && make install - - diff --git a/ogre_cfg/plugins.cfg b/ogre_cfg/plugins.cfg deleted file mode 100644 index 2cd4adf7993..00000000000 --- a/ogre_cfg/plugins.cfg +++ /dev/null @@ -1,18 +0,0 @@ -# Defines plugins to load - -# Define plugin folder -PluginFolder=. - -# Define plugins -# Plugin=RenderSystem_Direct3D9 -# Plugin=RenderSystem_Direct3D10 -# Plugin=RenderSystem_Direct3D11 - Plugin=RenderSystem_GL -#Plugin=OgreOggSound -# Plugin=RenderSystem_GLES - Plugin=Plugin_ParticleFX - #Plugin=Plugin_BSPSceneManager - #Plugin=Plugin_CgProgramManager - #Plugin=Plugin_PCZSceneManager - #Plugin=Plugin_OctreeZone - #Plugin=Plugin_OctreeSceneManager diff --git a/ogre_cfg/plugins_d.cfg b/ogre_cfg/plugins_d.cfg deleted file mode 100644 index f397c374013..00000000000 --- a/ogre_cfg/plugins_d.cfg +++ /dev/null @@ -1,18 +0,0 @@ -# Defines plugins to load - -# Define plugin folder -PluginFolder=. - -# Define plugins -# Plugin=RenderSystem_Direct3D9 -# Plugin=RenderSystem_Direct3D10 -# Plugin=RenderSystem_Direct3D11 - Plugin=RenderSystem_GL_d -# Plugin=OgreOggSound -# Plugin=RenderSystem_GLES - Plugin=Plugin_ParticleFX_d - #Plugin=Plugin_BSPSceneManager_d - #Plugin=Plugin_CgProgramManager_d - #Plugin=Plugin_PCZSceneManager_d - #Plugin=Plugin_OctreeZone_d - #Plugin=Plugin_OctreeSceneManager_d diff --git a/ogre_cfg/resources.cfg b/ogre_cfg/resources.cfg deleted file mode 100644 index 12599864e82..00000000000 --- a/ogre_cfg/resources.cfg +++ /dev/null @@ -1,29 +0,0 @@ -# Resource locations to be added to the default path -[General] - -FileSystem=../models -FileSystem=../models/skeletons -FileSystem=../materials/ -FileSystem=../materials/textures -FileSystem=../sounds -FileSystem=../videos -FileSystem=../tmp - -[Fonts] -FileSystem=../fonts -[Animations] -FileSystem=../gui/animations -[Imagesets] -FileSystem=../gui/imagesets -[Layouts] -FileSystem=../gui/layouts -[LookNFeel] -FileSystem=../gui/looknfeel -[Schemes] -FileSystem=../gui/schemes -[Animations] -FileSystem=../gui/animations - -[General] -# Keep this last so it overrides everything before -FileSystem=../testing \ No newline at end of file diff --git a/scripts/SimulationParameters/MicrobeStage/Bacteria.json b/scripts/SimulationParameters/MicrobeStage/Bacteria.json new file mode 100644 index 00000000000..7f15a01ce4c --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/Bacteria.json @@ -0,0 +1,44 @@ +{ + "rickettsia": { + "name": "Rickettsia", + "mesh": "i dunno", + "capacity": 50, + "mass": 0.4, + "health": 10, + "spawnDensity": 0.0001, + + "processes": { + "photosynthesis": 0.6 + }, + + "startingCompounds": { + "co2": 80 + }, + + "composition": { + "glucose": 2, + "oxygen": 1 + } + }, + + "cyanobacteria": { + "name": "Cyanobacteria", + "mesh": "i dunno", + "capacity": 50, + "mass": 0.4, + "health": 10, + "spawnDensity": 0.00012, + + "processes": { + "photosynthesis": 0.6 + }, + + "startingCompounds": { + "co2": 80 + }, + + "composition": { + "co2": 1 + } + } +} diff --git a/scripts/SimulationParameters/MicrobeStage/BioProcesses.json b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json new file mode 100644 index 00000000000..7dd011bfd8a --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/BioProcesses.json @@ -0,0 +1,71 @@ +{ + "respiration": { + "name": "Respiration", + + "inputs": { + "glucose": 1, + "oxygen": 6 + }, + + "outputs": { + "atp": 36, + "co2": 6 + } + }, + + "aminoAcidSynthesis": { + "name": "Amino acid synthesis", + + "inputs": { + "glucose": 1, + "ammonia": 1 + }, + + "outputs": { + "atp": 1, + "co2": 1, + "aminoacids": 1 + } + }, + + "fattyAcidSynthesis": { + "name": "Fatty acid synthesis", + + "inputs": { + "glucose": 1, + "ammonia": 1 + }, + + "outputs": { + "atp": 1, + "co2": 1, + "fattyacids": 1 + } + }, + + "photosynthesis": { + "name": "Photosynthesis", + + "inputs": { + "co2": 6 + }, + + "outputs": { + "glucose": 1, + "oxygen": 6 + } + }, + + "oxytoxySynthesis": { + "name": "Oxytoxy Synthesis", + + "inputs": { + "atp": 1, + "oxygen": 3 + }, + + "outputs": { + "oxytoxy": 1 + } + } +} diff --git a/scripts/SimulationParameters/MicrobeStage/Biomes.json b/scripts/SimulationParameters/MicrobeStage/Biomes.json new file mode 100644 index 00000000000..b2618e7a2f7 --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/Biomes.json @@ -0,0 +1,156 @@ +{ + "default": { + "name": "Ocean", + "background": "Background", + "colors":{ + "specularColors": { + "r": 0.98, + "g": 1, + "b": 0.95 + }, + "diffuseColors": { + "r": 1, + "g": 1, + "b": 1 + } + }, + + "compounds": { + "oxygen": { + "amount": 32500, + "density": 0.0002 + }, + + "co2": { + "amount": 32500, + "density": 0.0002 + }, + + "ammonia": { + "amount": 32500, + "density": 0.0002 + }, + + "glucose": { + "amount": 32500, + "density": 0.0002 + } + } + }, + + "volcanic_vent": { + "name": "Volcanic vent", + "background": "Background_Vent", + "colors":{ + "specularColors": { + "r": 0.98, + "g": 0.7, + "b": 0.75 + }, + "diffuseColors": { + "r": 1.0, + "g": 0.9, + "b": 0.9 + } + }, + + "compounds": { + "oxygen": { + "amount": 30000, + "density": 0.0002 + }, + + "co2": { + "amount": 75000, + "density": 0.0002 + }, + + "ammonia": { + "amount": 42500, + "density": 0.0002 + }, + + "glucose": { + "amount": 32500, + "density": 0.0002 + } + } + }, + + "abyss": { + "name": "Abyss", + "background": "Background_Abyss", + "colors":{ + "specularColors": { + "r": 0.48, + "g": 0.5, + "b": 0.95 + }, + "diffuseColors": { + "r": 0.5, + "g": 0.5, + "b": 0.5 + } + }, + "compounds": { + "oxygen": { + "amount": 25000, + "density": 0.0002 + }, + + "co2": { + "amount": 35000, + "density": 0.0002 + }, + + "ammonia": { + "amount": 35000, + "density": 0.0002 + }, + + "glucose": { + "amount": 40000, + "density": 0.0002 + } + } + }, + + "shallow": { + "name": "Shallow", + "background": "Background_Shallow", + "colors":{ + "specularColors": { + "r": 0.68, + "g": 1.0, + "b": 0.65 + }, + "diffuseColors": { + "r": 0.60, + "g": 1.0, + "b": 0.60 + } + }, + + "compounds": { + "oxygen": { + "amount": 50000, + "density": 0.0002 + }, + + "co2": { + "amount": 35000, + "density": 0.0002 + }, + + "ammonia": { + "amount": 30000, + "density": 0.0002 + }, + + "glucose": { + "amount": 35000, + "density": 0.0002 + } + } + } +} diff --git a/scripts/SimulationParameters/MicrobeStage/Compounds.json b/scripts/SimulationParameters/MicrobeStage/Compounds.json new file mode 100644 index 00000000000..7be2f3d2d10 --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/Compounds.json @@ -0,0 +1,97 @@ +{ + "atp": { + "name": "ATP", + "volume": 1, + "isCloud": false, + "isUseful": true, + "colour": { + "r": 0.235, + "g": 0.627, + "b": 0.705 + } + }, + + "oxygen": { + "name": "Oxygen", + "volume": 1, + "isCloud": true, + "isUseful": false, + "colour": { + "r": 0.235, + "g": 0.627, + "b": 0.705 + } + }, + + "aminoacids": { + "name": "Amino acids", + "volume": 1, + "isCloud": true, + "isUseful": true, + "colour": { + "r": 1.0, + "g": 0.588, + "b": 0.784 + } + }, + + "ammonia": { + "name": "Ammonia", + "volume": 1, + "isCloud": true, + "isUseful": false, + "colour": { + "r": 1.0, + "g": 0.862, + "b": 0.196 + } + }, + + "glucose": { + "name": "Glucose", + "volume": 1, + "isCloud": true, + "isUseful": false, + "colour": { + "r": 0.588, + "g": 0.666, + "b": 0.706 + } + }, + + "co2": { + "name": "CO2", + "volume": 1, + "isCloud": true, + "isUseful": false, + "colour": { + "r": 0.235, + "g": 0.627, + "b": 0.705 + } + }, + + "fattyacids": { + "name": "Fatty acids", + "volume": 1, + "isCloud": false, + "isUseful": false, + "colour": { + "r": 0.078, + "g": 0.196, + "b": 0.392 + } + }, + + "oxytoxy": { + "name": "Oxytoxy NT", + "volume": 1, + "isCloud": false, + "isUseful": true, + "colour": { + "r": 0.078, + "g": 0.0, + "b": 0.078 + } + } +} diff --git a/scripts/SimulationParameters/MicrobeStage/Organelles.json b/scripts/SimulationParameters/MicrobeStage/Organelles.json new file mode 100644 index 00000000000..d6b489a5d37 --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/Organelles.json @@ -0,0 +1,226 @@ +{ + "nucleus": { + "name": "Nucleus", + "mass": 0.7, + "gene": "N", + "mpCost": 0, + "mesh": "i dunno", + "locked": false, + + "composition": { + "aminoacids": 4 + }, + + "components": { + }, + + "hexes": [ + [0, 0], + [1, 0], + [0, 1], + [0, -1], + [1, -1], + [-1, 1], + [-1, 0], + [-1, -1], + [0, -2], + [1, -2] + ] + }, + + "chloroplast": { + "name": "Chloroplast", + "mass": 0.4, + "gene": "H", + "mpCost": 20, + "mesh": "i dunno", + "locked": true, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0], + [1, 0], + [0, 1] + ] + }, + + "oxytoxy": { + "name": "Agent vacuole", + "mass": 0.3, + "gene": "T", + "mpCost": 40, + "mesh": "i dunno", + "locked": true, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0] + ] + }, + + "mitochondrion": { + "name": "Mitochondrion", + "mass": 0.3, + "gene": "M", + "mpCost": 20, + "mesh": "i dunno", + "locked": false, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0], + [0, 1] + ] + }, + + "vacuole": { + "name": "Vacuole", + "mass": 0.4, + "gene": "V", + "mpCost": 15, + "mesh": "i dunno", + "locked": false, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0] + ] + }, + + "flagellum": { + "name": "Flagellum", + "mass": 0.3, + "gene": "F", + "mpCost": 25, + "mesh": "i dunno", + "locked": false, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0] + ] + }, + + "pilus": { + "name": "Pilus", + "mass": 0.3, + "gene": "P", + "mpCost": 30, + "mesh": "i dunno", + "locked": false, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0] + ] + }, + + "chemoplast": { + "name": "Chemoplast", + "mass": 0.3, + "gene": "C", + "mpCost": 15, + "mesh": "i dunno", + "locked": true, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0], + [1, 0], + [0, 1] + ] + }, + + "bioluminescent": { + "name": "Bioluminescent vacuole", + "mass": 0.4, + "gene": "L", + "mpCost": 15, + "mesh": "i dunno", + "locked": false, + + "composition": { + "aminoacids": 4, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0], + [1, 0], + [0, 1] + ] + }, + + "cytoplasm": { + "name": "Cytoplasm", + "mass": 0.4, + "gene": "Y", + "mpCost": 5, + "mesh": "", + "locked": false, + + "composition": { + "aminoacids": 3, + "glucose": 2 + }, + + "components": { + }, + + "hexes": [ + [0, 0] + ] + } +} diff --git a/scripts/SimulationParameters/MicrobeStage/Species.json b/scripts/SimulationParameters/MicrobeStage/Species.json new file mode 100644 index 00000000000..d44bbb88a3b --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/Species.json @@ -0,0 +1,19 @@ +{ + "default": { + "spawnDensity": 0.00007, + + "colour": { + "r": 1.0, + "g": 1.0, + "b": 1.0 + }, + + "startingCompounds": { + "aminoacids": 4, + "glucose": 2 + }, + + "organelles": { + } + } +} diff --git a/scripts/SimulationParameters/MicrobeStage/SpeciesNames.json b/scripts/SimulationParameters/MicrobeStage/SpeciesNames.json new file mode 100644 index 00000000000..0fbd457b77b --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/SpeciesNames.json @@ -0,0 +1,51 @@ +{ + "prefixes": [ + "Ce", + "Ar", + "Sp", + "Th", + "Co", + "So", + "Pu", + "Cr", + "Cy", + "Gr", + "Re", + "Ty", + "Tr", + "Ac", + "Pr" + ], + + "cofixes": [ + "nan", + "mo", + "na", + "yt", + "yn", + "il", + "li", + "le", + "op", + "un", + "rive", + "ec", + "ro", + "lar", + "im" + ], + + "suffixes": [ + "pien", + "olera", + "rius", + "nien", + "ster", + "ilia", + "canus", + "tus", + "cys", + "ium", + "um" + ] +} diff --git a/scripts/SimulationParameters/MicrobeStage/StartingCompounds.json b/scripts/SimulationParameters/MicrobeStage/StartingCompounds.json new file mode 100644 index 00000000000..bae75f542be --- /dev/null +++ b/scripts/SimulationParameters/MicrobeStage/StartingCompounds.json @@ -0,0 +1,5 @@ +{ + "atp": 40, + "oxygen": 10, + "glucose": 20 +} diff --git a/scripts/class.lua b/scripts/class.lua deleted file mode 100644 index 49b95907df2..00000000000 --- a/scripts/class.lua +++ /dev/null @@ -1,101 +0,0 @@ --- Class creation functions - --- see: http://lua-users.org/wiki/SimpleLuaClasses --- Modified to use .new for instantiating classes to be consistent with C++ classes -function class(base, create) - local c = {} -- a new class instance - if not create and type(base) == 'function' then - create = base - base = nil - elseif type(base) == 'table' then - -- our new class is a shallow copy of the base class! - for i,v in pairs(base) do - c[i] = v - end - c._base = base - else - error("class base is not a table or a constructor") - end - -- the class will be the metatable for all its objects, - -- and they will look up their methods in it. - c.__index = c - - -- expose a constructor - local mt = {} - c.new = function(...) - local obj = {} - setmetatable(obj, c) - if create then - -- The create method must explicitly call base create - create(obj,...) - else - -- make sure that any stuff from the base class is createialized! - if base and base.create then - base.create(obj, ...) - end - end - return obj - end - - -- Expose a table call constructor - mt.__call = function(class_tbl, ...) - - return class_tbl.new(...) - - end - - c.create = create - c.is_a = function(self, klass) - local m = getmetatable(self) - while m do - if m == klass then return true end - m = m._base - end - return false - end - setmetatable(c, mt) - return c -end - - - - - --- Helper file for creating Lua classes that inherit from C++ classes --- Creates a subclass of a C++ class -function createSubclass(baseClass) - - error("todo: fix this") - - assert(baseClass ~= nil, "tried to create subclass of nil") - - local newClass = {} - - local metaTable = { __index = newClass } - - -- Helper for creating instances - -- arg must be a table of values to pass to base class or nil - function newClass._createInstance(arg) - - -- Create base object first - if arg ~= nil then - local baseInstance = baseClass.new(unpack(arg)) - else - local baseInstance = baseClass.new() - end - - local newinst = {} - setmetatable(newinst, metaTable) - - -- Attach to the base class - setmetatable(newinst, { __index = baseInstance }) - - newinst["_asBase"] = baseInstance - - return newinst - end - - return newClass -end - - diff --git a/scripts/constants.lua b/scripts/constants.lua deleted file mode 100644 index 1b67c7e58e9..00000000000 --- a/scripts/constants.lua +++ /dev/null @@ -1,11 +0,0 @@ --- Define global constants here - -GAME_TITLE = "THRIVE" - --- Name of the player entity -PLAYER_NAME = Engine:playerData():playerName() - -NULL_ENTITY = 0 - --- Name of the main camera entity -CAMERA_NAME = "camera" diff --git a/scripts/game.lua b/scripts/game.lua deleted file mode 100644 index 6dd5040bda8..00000000000 --- a/scripts/game.lua +++ /dev/null @@ -1,85 +0,0 @@ --- Main file - -function printStartMessage() - - print("Thrive version " .. Engine.thriveVersion .. - " with " .. _VERSION .. " from " .. jit.version .. - " ready to go. " - --.. "Let's rock" - ) - -end - - --- Main loop for lua ---! @param cppGame thrive::Game object -function enterLuaMain(cppGame) - - printStartMessage() - - local fpsCount = 0 - - local lastUpdate = Game.now() - - -- For more accurate FPS counting - local lastSecond = Game.now() - - -- Counts frame times - local frameTimes = {} - - while cppGame.shouldQuit == false do - - local now = Game.now() - - local milliseconds = Game.asMS(Game.delta(now, lastUpdate)) - - lastUpdate = now - - -- Update engine stuff and GameStates - g_luaEngine:update(milliseconds) - - local frameDuration = Game.delta(Game.now(), now) - - table.insert(frameTimes, Game.asSeconds(frameDuration)) - - -- sleep if we are going too fast - cppGame:sleepIfNeeded(frameDuration) - - -- update fps counter - fpsCount = fpsCount + 1 - - local fpsTime = Game.asMS(Game.delta(now, lastSecond)) - if fpsTime >= 1000 then - - local fps = 1000 * (fpsCount / fpsTime) - - local avgFrameTime = 0 - - for i,t in ipairs(frameTimes) do - - avgFrameTime = avgFrameTime + t - - end - - avgFrameTime = (avgFrameTime / #frameTimes) * 1000 - - print(string.format("FPS: %.4f avg frame duration: %.5f ms", fps, - avgFrameTime)) - - -- Use to debug resource leaks in lua - --print("Used memory: " .. Engine.luaMemory) - - frameTimes = {} - lastSecond = now - fpsCount = 0 - end - end -end - - - - - - - - diff --git a/scripts/gui/MainMenu.layout b/scripts/gui/MainMenu.layout new file mode 100644 index 00000000000..6bba24e8adb --- /dev/null +++ b/scripts/gui/MainMenu.layout @@ -0,0 +1,1934 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/gui/gui_common.js b/scripts/gui/gui_common.js new file mode 100644 index 00000000000..9aba22f99e9 --- /dev/null +++ b/scripts/gui/gui_common.js @@ -0,0 +1,15 @@ +// Common helpers for the GUI to work with +"use strict"; + +//! Returns true if ran in Thrive (Leviathan is available) false if inside a desktop browser +function isInEngine(){ + return typeof Leviathan === 'object' && Leviathan !== null; +} + +//! Shows an alert if isInEngine is false +function requireEngine(msg){ + if(!isInEngine()){ + + alert("This method only works inside Thrive, msg: " + msg); + } +} diff --git a/scripts/gui/main_menu.js b/scripts/gui/main_menu.js new file mode 100644 index 00000000000..b54173df441 --- /dev/null +++ b/scripts/gui/main_menu.js @@ -0,0 +1,15 @@ +// Main menu scripts are here +"use strict"; + + +//! Setup callbacks for buttons +function runMenuSetup(){ + + document.getElementById("quitButton").addEventListener("click", quitGame, true); +} + +function quitGame(){ + requireEngine(); + Leviathan.Quit(); +} + diff --git a/scripts/gui/microbe_gui_events.as b/scripts/gui/microbe_gui_events.as new file mode 100644 index 00000000000..67199aae7f2 --- /dev/null +++ b/scripts/gui/microbe_gui_events.as @@ -0,0 +1,305 @@ +CEGUI::Window@ atpBar; +// Workaround to not being able to call the base class methods from derived +CEGUI::ProgressBar@ atpBarAsBar; +CEGUI::Window@ atpCountLabel; +CEGUI::Window@ atpMaxLabel; +CEGUI::Window@ atpCountLabel2; + +CEGUI::Window@ oxygenBar; +CEGUI::ProgressBar@ oxygenBarAsBar; +CEGUI::Window@ oxygenCountLabel; +CEGUI::Window@ oxygenMaxLabel; + +CEGUI::Window@ aminoacidsBar; +CEGUI::ProgressBar@ aminoacidsBarAsBar; +CEGUI::Window@ aminoacidsCountLabel; +CEGUI::Window@ aminoacidsMaxLabel; + +CEGUI::Window@ ammoniaBar; +CEGUI::ProgressBar@ ammoniaBarAsBar; +CEGUI::Window@ ammoniaCountLabel; +CEGUI::Window@ ammoniaMaxLabel; + +CEGUI::Window@ glucoseBar; +CEGUI::ProgressBar@ glucoseBarAsBar; +CEGUI::Window@ glucoseCountLabel; +CEGUI::Window@ glucoseMaxLabel; + +CEGUI::Window@ co2Bar; +CEGUI::ProgressBar@ co2BarAsBar; +CEGUI::Window@ co2CountLabel; +CEGUI::Window@ co2MaxLabel; + +CEGUI::Window@ fattyacidsBar; +CEGUI::ProgressBar@ fattyacidsBarAsBar; +CEGUI::Window@ fattyacidsCountLabel; +CEGUI::Window@ fattyacidsMaxLabel; + +CEGUI::Window@ oxytoxyBar; +CEGUI::ProgressBar@ oxytoxyBarAsBar; +CEGUI::Window@ oxytoxyCountLabel; +CEGUI::Window@ oxytoxyMaxLabel; + + +CEGUI::Window@ hitpointsBar; +CEGUI::ProgressBar@ hitpointsBarAsBar; +CEGUI::Window@ hitpointsCountLabel; +CEGUI::Window@ hitpointsMaxLabel; + + +[@Listener="OnInit"] +int setupHUDBars(GuiObject@ instance){ + + auto microbeRootWindow = + instance.GetOwningManager().GetRootWindow().GetChild("MicrobeStageRoot"); + + assert(microbeRootWindow !is null, "MicrobeStageRoot window is missing"); + + auto compoundsScroll = + microbeRootWindow.GetChild("CompoundPanel/CompoundScroll"); + + assert(compoundsScroll !is null, "Compound panel not found (CompoundsScroll)"); + + + @atpBar = compoundsScroll.GetChild("ATPBar/ATPBar"); + @atpBarAsBar = cast(atpBar); + + @oxygenBar = compoundsScroll.GetChild("OxygenBar/OxygenBar"); + @oxygenBarAsBar = cast(oxygenBar); + + @aminoacidsBar = compoundsScroll.GetChild("AminoAcidsBar/AminoAcidsBar"); + @aminoacidsBarAsBar = cast(aminoacidsBar); + + @ammoniaBar = compoundsScroll.GetChild("AmmoniaBar/AmmoniaBar"); + @ammoniaBarAsBar = cast(ammoniaBar); + + @glucoseBar = compoundsScroll.GetChild("GlucoseBar/GlucoseBar"); + @glucoseBarAsBar = cast(glucoseBar); + + @co2Bar = compoundsScroll.GetChild("CO2Bar/CO2Bar"); + @co2BarAsBar = cast(co2Bar); + + @fattyacidsBar = compoundsScroll.GetChild("FattyAcidsBar/FattyAcidsBar"); + @fattyacidsBarAsBar = cast(fattyacidsBar); + + @oxytoxyBar = compoundsScroll.GetChild("OxyToxyNTBar/OxyToxyNTBar"); + @oxytoxyBarAsBar = cast(oxytoxyBar); + + @hitpointsBar = microbeRootWindow.GetChild("HealthPanel/LifeBar"); + @hitpointsBarAsBar = cast(hitpointsBar); + + assert(atpBar !is null && atpBarAsBar !is null, "GUI didn't find atpBar"); + assert(oxygenBar !is null && oxygenBarAsBar !is null, "GUI didn't find oxygenBar"); + assert(aminoacidsBar !is null && aminoacidsBarAsBar !is null, + "GUI didn't find aminoacidsBar"); + assert(ammoniaBar !is null && ammoniaBarAsBar !is null, "GUI didn't find ammoniaBar"); + assert(glucoseBar !is null && glucoseBarAsBar !is null, "GUI didn't find glucoseBar"); + assert(co2Bar !is null && co2BarAsBar !is null, "GUI didn't find co2Bar"); + assert(fattyacidsBar !is null && fattyacidsBarAsBar !is null, + "GUI didn't find fattyacidsBar"); + assert(oxytoxyBar !is null && oxytoxyBarAsBar !is null, "GUI didn't find oxytoxyBar"); + assert(hitpointsBar !is null && hitpointsBarAsBar !is null, + "GUI didn't find hitpointsBar"); + + @atpCountLabel = atpBar.GetChild("NumberLabel"); + @atpMaxLabel = compoundsScroll.GetChild("ATPBar/ATPTotal"); + @atpCountLabel2 = microbeRootWindow.GetChild("HealthPanel/ATPValue"); + + @oxygenCountLabel = oxygenBar.GetChild("NumberLabel"); + @oxygenMaxLabel = compoundsScroll.GetChild("OxygenBar/OxygenTotal"); + + @aminoacidsCountLabel = aminoacidsBar.GetChild("NumberLabel"); + @aminoacidsMaxLabel = compoundsScroll.GetChild("AminoAcidsBar/AminoAcidsTotal"); + + @ammoniaCountLabel = ammoniaBar.GetChild("NumberLabel"); + @ammoniaMaxLabel = compoundsScroll.GetChild("AmmoniaBar/AmmoniaTotal"); + + @glucoseCountLabel = glucoseBar.GetChild("NumberLabel"); + @glucoseMaxLabel = compoundsScroll.GetChild("GlucoseBar/GlucoseTotal"); + + @co2CountLabel = co2Bar.GetChild("NumberLabel"); + @co2MaxLabel = compoundsScroll.GetChild("CO2Bar/CO2Total"); + + @fattyacidsCountLabel = fattyacidsBar.GetChild("NumberLabel"); + @fattyacidsMaxLabel = compoundsScroll.GetChild("FattyAcidsBar/FattyAcidsTotal"); + + @oxytoxyCountLabel = oxytoxyBar.GetChild("NumberLabel"); + @oxytoxyMaxLabel = compoundsScroll.GetChild("OxyToxyNTBar/OxyToxyNTTotal"); + + @hitpointsCountLabel = hitpointsBar.GetChild("NumberLabel"); + @hitpointsMaxLabel = microbeRootWindow.GetChild("HealthPanel/HealthTotal"); + + + assert(atpCountLabel !is null, "GUI didn't find atpCountLabel"); + assert(atpMaxLabel !is null, "GUI didn't find atpMaxLabel"); + assert(atpCountLabel2 !is null, "GUI didn't find atpCountLabel2"); + assert(oxygenCountLabel !is null, "GUI didn't find oxygenCountLabel"); + assert(oxygenMaxLabel !is null, "GUI didn't find oxygenMaxLabel"); + assert(aminoacidsCountLabel !is null, "GUI didn't find aminoacidsCountLabel"); + assert(aminoacidsMaxLabel !is null, "GUI didn't find aminoacidsMaxLabel"); + assert(ammoniaCountLabel !is null, "GUI didn't find ammoniaCountLabel"); + assert(ammoniaMaxLabel !is null, "GUI didn't find ammoniaMaxLabel"); + assert(glucoseCountLabel !is null, "GUI didn't find glucoseCountLabel"); + assert(glucoseMaxLabel !is null, "GUI didn't find glucoseMaxLabel"); + assert(co2CountLabel !is null, "GUI didn't find co2CountLabel"); + assert(co2MaxLabel !is null, "GUI didn't find co2aMaxLabel"); + assert(fattyacidsCountLabel !is null, "GUI didn't find fattyacidsCountLabel"); + assert(fattyacidsMaxLabel !is null, "GUI didn't find fattyacidsMaxLabel"); + assert(oxytoxyCountLabel !is null, "GUI didn't find oxytoxyCountLabel"); + assert(oxytoxyMaxLabel !is null, "GUI didn't find oxytoxyMaxLabel"); + assert(hitpointsCountLabel !is null, "GUI didn't find hitpointsCountLabel"); + assert(hitpointsMaxLabel !is null, "GUI didn't find hitpointsMaxLabel"); + + // TODO: shouldn't these background images be set in the .layout file? + atpBar.SetProperty("FillImage", "ThriveGeneric/ATPBar"); + oxygenBar.SetProperty("FillImage", "ThriveGeneric/OxygenBar"); + aminoacidsBar.SetProperty("FillImage", "ThriveGeneric/AminoAcidsBar"); + ammoniaBar.SetProperty("FillImage", "ThriveGeneric/AmmoniaBar"); + glucoseBar.SetProperty("FillImage", "ThriveGeneric/GlucoseBar"); + co2Bar.SetProperty("FillImage", "ThriveGeneric/CO2Bar"); + fattyacidsBar.SetProperty("FillImage", "ThriveGeneric/FattyAcidsBar"); + oxytoxyBar.SetProperty("FillImage", "ThriveGeneric/OxyToxyBar"); + hitpointsBar.SetProperty("FillImage", "ThriveGeneric/HitpointsBar"); + + return 1; +} + +[@Listener="Generic", @Type="PlayerCompoundAmounts"] +int handleCompoundBarsUpdate(GuiObject@ instance, GenericEvent@ event){ + NamedVars@ vars = event.GetNamedVars(); + auto atp = vars.GetSingleValueByName("compoundATP"); + auto atpMax = vars.GetSingleValueByName("ATPMax"); + auto oxygen = vars.GetSingleValueByName("compoundOxygen"); + auto oxygenMax = vars.GetSingleValueByName("OxygenMax"); + auto aminoacids = vars.GetSingleValueByName("compoundAminoacids"); + auto aminoacidsMax = vars.GetSingleValueByName("AminoacidsMax"); + auto ammonia = vars.GetSingleValueByName("compoundAmmonia"); + auto ammoniaMax = vars.GetSingleValueByName("AmmoniaMax"); + auto glucose = vars.GetSingleValueByName("compoundGlucose"); + auto glucoseMax = vars.GetSingleValueByName("GlucoseMax"); + auto co2 = vars.GetSingleValueByName("compoundCo2"); + auto co2Max = vars.GetSingleValueByName("Co2Max"); + auto fattyacids = vars.GetSingleValueByName("compoundFattyacids"); + auto fattyacidsMax = vars.GetSingleValueByName("FattyacidsMax"); + auto oxytoxy = vars.GetSingleValueByName("compoundOxytoxy"); + auto oxytoxyMax = vars.GetSingleValueByName("OxytoxyMax"); + auto hitpoints = vars.GetSingleValueByName("hitpoints"); + auto hitpointsMax = vars.GetSingleValueByName("hitpointsMax"); + + // Debug print for all the variables + // LOG_WRITE("Event data: \n" + vars.Serialize(" ")); + + if(atp !is null && atpMax !is null){ + + auto atpAmount = double(atp); + auto max = double(atpMax); + + atpBarAsBar.SetProgress(atpAmount / max); + atpCountLabel.SetText(formatFloat(floor(atpAmount))); + atpMaxLabel.SetText("/" + formatFloat(floor(atpMax))); + + atpCountLabel2.SetText(formatFloat(floor(atpAmount))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing atp value"); + } + + if(oxygen !is null && oxygenMax !is null){ + auto oxygenAmount = double(oxygen); + auto max = double(oxygenMax); + + oxygenBarAsBar.SetProgress(oxygenAmount / max); + oxygenCountLabel.SetText(formatFloat(floor(oxygenAmount))); + + oxygenMaxLabel.SetText("/" + formatFloat(floor(oxygenMax))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing oxygen value"); + } + + if(aminoacids !is null && aminoacidsMax !is null){ + auto aminoacidsAmount = double(aminoacids); + auto max = double(aminoacidsMax); + + aminoacidsBarAsBar.SetProgress(aminoacidsAmount / max); + aminoacidsCountLabel.SetText(formatFloat(floor(aminoacidsAmount))); + aminoacidsMaxLabel.SetText("/" + formatFloat(floor(aminoacidsMax))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing aminoacids value"); + } + + if(ammonia !is null && ammoniaMax !is null){ + auto ammoniaAmount = double(aminoacids); + auto max = double(ammoniaMax); + + ammoniaBarAsBar.SetProgress(ammoniaAmount / max); + ammoniaCountLabel.SetText(formatFloat(floor(ammoniaAmount))); + ammoniaMaxLabel.SetText("/" + formatFloat(floor(ammoniaMax))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing ammonia value"); + } + + if(glucose !is null && glucoseMax !is null){ + auto glucoseAmount = double(glucose); + auto max = double(glucoseMax); + + glucoseBarAsBar.SetProgress(glucoseAmount / max); + glucoseCountLabel.SetText(formatFloat(floor(glucoseAmount))); + glucoseMaxLabel.SetText("/" + formatFloat(floor(glucoseMax))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing glucose value"); + } + + if(co2 !is null && co2Max !is null){ + auto co2Amount = double(co2); + auto max = double(co2Max); + + co2BarAsBar.SetProgress(co2Amount / max); + co2CountLabel.SetText(formatFloat(floor(co2Amount))); + co2MaxLabel.SetText("/" + formatFloat(floor(co2Max))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing co2 value"); + } + + if(fattyacids !is null && fattyacidsMax !is null){ + auto fattyacidsAmount = double(fattyacids); + auto max = double(fattyacidsMax); + + fattyacidsBarAsBar.SetProgress(fattyacidsAmount / max); + fattyacidsCountLabel.SetText(formatFloat(floor(fattyacidsAmount))); + fattyacidsMaxLabel.SetText("/" + formatFloat(floor(fattyacidsMax))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing fattyacids value"); + } + + if(oxytoxy !is null && oxytoxyMax !is null){ + auto oxytoxyAmount = double(oxytoxy); + auto max = double(oxytoxyMax); + + oxytoxyBarAsBar.SetProgress(oxytoxyAmount / max); + oxytoxyCountLabel.SetText(formatFloat(floor(oxytoxyAmount))); + oxytoxyMaxLabel.SetText("/" + formatFloat(floor(oxytoxyMax))); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing oxytoxy value"); + } + + if(hitpoints !is null && hitpointsMax !is null){ + auto hitpointsAmount = int(hitpoints); + auto max = int(hitpointsMax); + + hitpointsBarAsBar.SetProgress(hitpointsAmount / max); + hitpointsCountLabel.SetText(formatInt(hitpointsAmount)); + hitpointsMaxLabel.SetText("/" + formatInt(hitpointsMax)); + + } else { + LOG_WARNING("Microbe HUD compound amount update is missing hitpoints value"); + } + + return 1; +} diff --git a/scripts/gui/thrive_gui.html b/scripts/gui/thrive_gui.html new file mode 100644 index 00000000000..13527cc152d --- /dev/null +++ b/scripts/gui/thrive_gui.html @@ -0,0 +1,38 @@ + + + + + Thrive GUI + + + + + + + + + + + +

+ + diff --git a/scripts/gui/thrive_menus.txt b/scripts/gui/thrive_menus.txt new file mode 100644 index 00000000000..2d757b097ff --- /dev/null +++ b/scripts/gui/thrive_menus.txt @@ -0,0 +1,462 @@ +// Main menu script of Thrive +GUIBaseFile = "MainMenu.layout"; +GUIAnimations = ["thrive.anims"]; +RequireCEGUIHooked = true; +ExtraAccess = "FullFileSystem"; + +// This keeps the GUI always on (no mouse capture is used on the main menu) +o GuiCollection "OnKeeper"{ + l params{ + Enabled = true; + KeepsGUIOn = true; + } +} + +// Top level window for all menus +o GuiCollection "Background"{ + l params{ + Enabled = true; + AutoTarget = "Background"; + } + + s{ + AudioSource @jams; + + // Called from the intro video player after it ends + [@Listener="Generic", @Type="IntroVideoFinished"] + int startMenuMusic(){ + + LOG_INFO("Starting menu music"); + @jams = GetEngine().GetSoundDevice().Play2DSound("Data/Sound/main-menu-theme-2.ogg", + true, false); + return 1; + } + + // These pause and resume the main menu music + [@Listener="OnHide"] + int pauseMenuMusic(){ + + jams.Get().pause(); + return 1; + } + + [@Listener="OnShow"] + int resumeMenuMusic(){ + + jams.Get().play(); + return 1; + } + + @%}; +} + +// main menu root window +o GuiCollection "TopLevelMenu"{ + l params{ + Enabled = true; + AutoTarget = "Background/MainMenuInteractive"; + //AutoAnimateChildren = true; + //AutoAnimationIn = [[AutoTarget], [PopIn]]; + //AutoAnimationOut = [[AutoTarget], [SinkAway]]; + } +} + +// Root of the cell stage GUI +o GuiCollection "MicrobeRoot"{ + l params{ + Enabled = false; + AutoTarget = "MicrobeStageRoot"; + } +} + +// Root of the microbe editor GUI +o GuiCollection "MicrobeEditorRoot"{ + l params{ + Enabled = false; + AutoTarget = "MicrobeEditorRoot"; + } + s{ + GuiCollection@ ourInstance; + + [@Listener="OnInit"] + int storeInstance(GuiCollection@ instance){ + @ourInstance = instance; + return 1; + } + + void restoreFinishButtonActual(){ + LOG_INFO("Enabling finish button after half a second"); + ourInstance.GetOwningManager().GetRootWindow().GetChild( + "MicrobeEditorRoot/FinishButton").SetDisabledState(false); + } + + void restoreFinishButtonBackgroundCall(){ + // Called in a background thread so we need to invoke + GetEngine().Invoke(@restoreFinishButtonActual); + } + + // Called from ThriveGame when the editor is entered + [@Listener="Generic", @Type="MicrobeEditorEntered"] + int enterEditor(/* Don't need the instance as it is already stored */){ + + ourInstance.UpdateState(true); + + // Disable the normal microbe GUI + ourInstance.GetOwningManager().SetCollectionState("MicrobeRoot", false); + + // Disable the finish button + ourInstance.GetOwningManager().GetRootWindow().GetChild( + "MicrobeEditorRoot/FinishButton").SetDisabledState(true); + + // And enable it in half a second + GetEngine().GetThreadingManager().QueueTaskDelayed( + @restoreFinishButtonBackgroundCall, 500); + + return 1; + } + + // Called from ThriveGame when the editor is exited + [@Listener="Generic", @Type="MicrobeEditorExited"] + int enterExitEditor(/* Don't need the instance as it is already stored */){ + + ourInstance.UpdateState(false); + + // Enable the normal microbe GUI + ourInstance.GetOwningManager().SetCollectionState("MicrobeRoot", true); + return 1; + } + @%}; +} + +// ------------------------------------ // +// This creates the intro video player +// And also plays the menu sound because why not +o GuiObject "_IntroVideoStarter"{ + s{ + GuiObject@ OurObject; + bool PlayingIntroVideo = false; + + // Comment the next line to not play intro video + [@Listener="OnInit"] + int StartVideoPlayback(GuiObject@ instance){ + + LOG_INFO("Starting to play intro video"); + CEGUI::Window@ videoPlayer = instance.GetOwningManager().GetRootWindow(). + CreateAndAddChild("Thrive/VideoPlayer", "MainMenuVideoPlayer"); + + videoPlayer.SetSize(1.0, 0, 1.0, 0); + + auto@ castedPlayer = cast(videoPlayer); + + // Grab the created window as our own + instance.ConnectElement(videoPlayer); + + if(!instance.IsCEGUIEventHooked()){ + + LOG_ERROR("IntroVideoStarter failed to bind to the created video " + "player widget"); + return 0; + } + + // Save object for callback // + @OurObject = instance; + + // Register end callback // + castedPlayer.OnPlaybackEnded.Register(@OnVideoEnded); + + // Start playback + castedPlayer.Play("Data/Videos/intro.mkv"); + PlayingIntroVideo = true; + + return 1; + } + + // This is probably not called as it isn't a button + [@Listener="OnClick"] + bool VideoPlayerClicked(GuiObject@ instance){ + + LOG_INFO("VideoPlayer clicked"); + return true; + } + + void DestroyVideoPlayerWindow(){ + // Make sure this is called only once + if(!PlayingIntroVideo) + return; + + PlayingIntroVideo = false; + LOG_INFO("Destroying VideoPlayer window"); + OurObject.GetOwningManager().GetRootWindow(). + DestroyChild("MainMenuVideoPlayer"); + + //play music too + GetEngine().GetEventHandler().CallEvent(GenericEvent("IntroVideoFinished")); + } + + // Called by the videoplayer when the playback ends + void OnVideoEnded(NamedVars@ values){ + + LOG_INFO("Intro video ended"); + GetEngine().Invoke(@DestroyVideoPlayerWindow); + } + + // User pressed skip intro video button + [@Listener="Generic", @Type="MainMenuIntroSkipEvent"] + int onSkipVideoEvent(GuiObject@ instance, GenericEvent@ event){ + if(PlayingIntroVideo){ + OnVideoEnded(NamedVars()); + return 1; + } else { + return 0; + } + } + @%}; +} + + + + +// ------------------------------------ // +// Main menu objects +// Version label +o GuiObject "Background/MainMenuInteractive/VersionLabel"{ + s{ + [@Listener="OnInit"] + int WriteVersion(GuiObject@ instance){ + instance.GetTargetWindow().SetText("TODO: ver (" + GetLeviathanVersion() + + ")"); + + return 1; + } + @%}; +} +//Load the game// +o GuiObject "Background/MainMenuInteractive/LoadGameButton"{ + s{ + + [@Listener="OnInit"] + int checkforSave(GuiObject@ instance){ + // disable if no saved game // + //for some reaosn I cannot call FileSystem::FileExists even though it works fine in the other angel scripts - Michael + // This now works with new ExtraAccess setting (also it was a static function so it + // is called like this) - hhyyrylainen + if (!FileSystem::FileExists("quick.sav")) { + instance.GetTargetWindow().SetDisabledState(true); + } + return 1; + } + [@Listener="OnClick"] + bool LoadIt(GuiObject@ instance){ + GetEngine().GetSoundDevice().Play2DSoundEffect("Data/Sound/soundeffects/gui/button-hover-click.ogg"); + // Load the game // + if (FileSystem::FileExists("quick.sav")) { + // Disable all the menus + instance.GetOwningManager().SetCollectionState("Background", false); + // And show the microbe GUI + instance.GetOwningManager().SetCollectionState("MicrobeRoot", true); + GetThriveGame().loadSaveGame("quick.sav"); + } + return true; + } + @%}; +} + +// Quit the game // +o GuiObject "Background/MainMenuInteractive/ExitGameButton"{ + s{ + [@Listener="OnClick"] + bool QuitIt(GuiObject@ instance){ + // Close the game // + GetEngine().GetSoundDevice().Play2DSoundEffect("Data/Sound/soundeffects/gui/button-hover-click.ogg"); + cast(GetThriveGame()).MarkAsClosing(); + return true; + } + @%}; +} + +// Start game // +o GuiObject "Background/MainMenuInteractive/NewGameButton"{ + s{ + bool PlayingVideo = false; + GuiObject@ VideoPlayerWindow; + GuiObject@ OurInstance; + + [@Listener="OnClick"] + bool StartGame(GuiObject@ instance){ + //play click sound + GetEngine().GetSoundDevice().Play2DSoundEffect("Data/Sound/soundeffects/gui/button-hover-click.ogg"); + // Store this for the ended callback + @OurInstance = instance; + + //initialize the video player + LOG_INFO("initialized video player"); + CEGUI::Window@ microbeIntroVideoPlayer = instance.GetOwningManager().GetRootWindow(). + CreateAndAddChild("Thrive/VideoPlayer", "IntroPlayer"); + LOG_INFO("initialized video player"); + microbeIntroVideoPlayer.SetSize(1.0, 0, 1.0, 0); + LOG_INFO("set size of video player"); + auto@ castedPlayer = cast(microbeIntroVideoPlayer); + LOG_INFO("casted player created"); + // We are already attached to a CEGUI window so we don't grab the videoplayer + // like in MainMenuVideoPlayer + + @VideoPlayerWindow = instance; + // Register end callback // + castedPlayer.OnPlaybackEnded.Register(@OnMicrobeVideoEnded); + + // Start playback + castedPlayer.Play("Data/Videos/MicrobeIntro.mkv"); + PlayingVideo = true; + return true; + } + //microbe video stuff + void DestroyMicrobeVideo(){ + // Make sure this is called only once + if(!PlayingVideo) + return; + + PlayingVideo = false; + VideoPlayerWindow.GetOwningManager().GetRootWindow().DestroyChild("IntroPlayer"); + LOG_INFO("Destroying VideoPlayer window"); + + } + + void OnMicrobeVideoEnded(NamedVars@ values){ + LOG_INFO("Stage video ended"); + GetEngine().Invoke(@DestroyMicrobeVideo); + + // And now swap the GUI // + // Disable all the menus + OurInstance.GetOwningManager().SetCollectionState("Background", false); + // And show the microbe GUI + OurInstance.GetOwningManager().SetCollectionState("MicrobeRoot", true); + + GetThriveGame().startNewGame(); + } + + // User pressed skip intro video button + [@Listener="Generic", @Type="MainMenuIntroSkipEvent"] + int onSkipVideoMicrobeEvent(GuiObject@ instance, GenericEvent@ event){ + if(PlayingVideo){ + OnMicrobeVideoEnded(NamedVars()); + return 1; + } else { + return 0; + } + } + // Uncomment the next line to automatically start a new game + // also remember to disable the intro video to not hear it also play + // [@Listener="OnInit"] + int InstantStart(GuiObject@ instance){ + + // Store this for the ended callback + @OurInstance = instance; + OnMicrobeVideoEnded(NamedVars()); + return 1; + } + + @%}; +} + +//function MainMenuHudSystem:update(renderTime, logicTime) +// if keyCombo(kmp.screenshot) then +// Engine:screenShot("screenshot.png") +// elseif keyCombo(kmp.skipvideo) then +// if self.videoPlayer then +// self.videoPlayer:close() +// self.videoPlayer:hide() +// +// getComponent("gui_sounds", self.gameState, SoundSourceComponent +// ):interruptPlaying() +// +// getComponent("main_menu_ambience", self.gameState, SoundSourceComponent +// ).autoLoop = true +// self.skippedVideo = true +// end +// elseif keyCombo(kmp.forward) then +// end +// if self.videoPlayer then +// self.videoPlayer:update() +// if self.videoPlayer:getCurrentTime() >= self.videoPlayer:getDuration() - 3.0 then +// if not self.vidFadeoutStarted then +// self.videoPlayer:playAnimation("fadeout") +// self.vidFadeoutStarted = true +// end +// if not self.skippedVideo and self.videoPlayer:getCurrentTime() >= self.videoPlayer:getDuration() then +// self.videoPlayer:hide() +// +// getComponent("main_menu_ambience", self.gameState, SoundSourceComponent +// ).autoLoop = true +// +// end +// end +// end +//end + +//local function setupSound(gameState) +// -- Background music +// local ambientEntity = Entity.new("main_menu_ambience", gameState.wrapper) +// local soundSource = SoundSourceComponent.new() +// soundSource.ambientSoundSource = true +// soundSource.autoLoop = false +// soundSource.volumeMultiplier = 0.15 +// ambientEntity:addComponent(soundSource) +// soundSource:addSound("main-menu-theme-1", "main-menu-theme-1.ogg") +// soundSource:addSound("main-menu-theme-2", "main-menu-theme-2.ogg") +// -- Gui effects +// local guiSoundEntity = Entity.new("gui_sounds", gameState.wrapper) +// soundSource = SoundSourceComponent.new() +// soundSource.ambientSoundSource = true +// soundSource.autoLoop = false +// soundSource.volumeMultiplier = 1.0 +// guiSoundEntity:addComponent(soundSource) +// -- Sound +// soundSource:addSound("button-hover-click", "soundeffects/gui/button-hover-click.ogg") +//end +// ------------------------------------ // + + +// ------------------------------------ // +// MicrobeStage HUD things +o GuiObject "_mainMicrobeHUDEventHandler"{ + s{ + // This is a good example of how to put complex scripts to a new + #include "microbe_gui_events.as" + @%}; +} + +o GuiObject "MicrobeStageRoot/EditorButton"{ + s{ + [@Listener="Generic", @Type="PlayerReadyToEnterEditor"] + int enable(GuiObject@ instance, GenericEvent@ event){ + instance.GetTargetWindow().SetDisabledState(false); + return 1; + } + + [@Listener="OnClick"] + bool clicked(GuiObject@ instance){ + GetThriveGame().editorButtonClicked(); + instance.GetTargetWindow().SetDisabledState(true); + return true; + } + @%}; +} + +// ------------------------------------ // +// MicrobeEditor HUD things +o GuiObject "MicrobeEditorRoot/FinishButton"{ + s{ + [@Listener="OnClick"] + bool clicked(GuiObject@ instance){ + GetThriveGame().finishEditingClicked(); + instance.GetTargetWindow().SetDisabledState(true); + return true; + } + @%}; +} + + + + + + diff --git a/scripts/gui/thrive_style.css b/scripts/gui/thrive_style.css new file mode 100644 index 00000000000..2138f3f96f0 --- /dev/null +++ b/scripts/gui/thrive_style.css @@ -0,0 +1,144 @@ +/* Thrive stylesheet */ + +/* Fonts */ +@font-face { + font-family: "thrive"; + src: url("../../Fonts/thrive.ttf") format("truetype"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: "Jura"; + src: url("../../Fonts/Jura-DemiBold.ttf") format("truetype"); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: "Jura"; + src: url("../../Fonts/Jura-Regular.ttf") format("truetype"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: "Jura"; + src: url("../../Fonts/Jura-Light.ttf") format("truetype"); + font-weight: lighter; + font-style: normal; +} + +@font-face { + font-family: "Jura"; + src: url("../../Fonts/Jura-Medium.ttf") format("truetype"); + font-weight: bolder; + font-style: normal; +} + +/* Element styling */ +html{ + background-image: url("../../Textures/gui/ThriveBackground.png"); + width: 100%; + height: 100%; + font-family: "Jura"; +} + +button{ + background-color: blue; +} + + +/* Menu things */ +.MenuContainer{ + display: flex; + justify-content: center; + width: auto; +} + +.MainMenu{ + + margin-top: 120px; + width: auto; +} + +.MenuButton { + /*position: relative;*/ + /*left:50%;*/ + /*top:50vh;*/ + width: 150px; + height: 40px; + /* margin-left:-110px;*/ + margin-bottom:5px; + color: white; + background-color: rgb(0, 125, 125, 0.4); + text-align: center; + vertical-align: middle; + line-height: 40px; +} + +.DisabledButton { + + background-color: rgb(0, 80, 80, 0.32); +} + +.MenuButton:hover { + background-color: rgb(0, 125, 125, 0.8); +} + +.DisabledButton:hover { + background-color: rgb(0, 80, 80, 0.32); +} + + +/* tjwhale's sample + +.menuButton { + position: relative; + left:50%; + top:50vh; + width:150px; + height:40px; + margin-left:-110px; + margin-bottom:5px; + color:white; + background-color:rgb(0,125,125,0.4); + text-align:center; + vertical-align:middle; + line-height:40px; +} + +.menuButton:before { + content:""; + position: absolute; + right: 100%; + top:0px; + width:0px; + height:0px; + border-top:20px solid transparent; + border-right:35px solid rgb(0,125,125,0.4); + border-bottom:20px solid transparent; +} + +.menuButton:after { + content:""; + position: absolute; + left: 100%; + top:0px; + width:0px; + height:0px; + border-top:20px solid transparent; + border-left:35px solid rgb(0,125,125,0.4); + border-bottom:20px solid transparent; +} +.menuButton:hover { + background-color:rgb(0,125,125,0.8); +} +.menuButton:hover:before { + border-right:35px solid rgb(0,125,125,0.8); +} +.menuButton:hover:after { + border-left:35px solid rgb(0,125,125,0.8); +} +*/ + diff --git a/scripts/lua_engine/game_state.lua b/scripts/lua_engine/game_state.lua deleted file mode 100644 index 34d4a2e6a42..00000000000 --- a/scripts/lua_engine/game_state.lua +++ /dev/null @@ -1,247 +0,0 @@ ---! @file Gamestate, holds systems and updates the game systems and draws stuff - --- This is what is said about the state in the C++ code: --- GameState Represents a distinct set of active systems and entities --- --- The game has to switch between different states. Examples of a state are --- "main menu", "microbe gameplay" or "microbe editor". These states usually --- share very few entities and even fewer systems, so it is sensible to --- separate them completely (and, if necessary, share data over other channels). --- --- Each GameState has its own EntityManager and its own set of systems. Game --- states are identified by their name, a unique string. --- --- GameStates cannot be created directly. Use LuaEngine:createGameState to create --- new GameStates. - - -GameState = class( - --! @brief Constructs a new GameState. Must be called from derived classes with - --! `GameState.create(self)` - --! @note calls this only through LuaEngine:createGameState - function(self, name, systems, engine, physics, guiLayoutName, extraInitializer) - - assert(name ~= nil) - assert(systems ~= nil) - assert(type(systems) == "table") - assert(engine ~= nil) - -- Physics must be true or false - assert(physics ~= nil) - -- TODO: make "none" skip creating the CEGUIWindow - assert(guiLayoutName ~= nil) - - self.extraInitializer = extraInitializer - - -- Systems container - self.systems = systems - self.name = name - self.engine = engine - self.guiLayoutName = guiLayoutName - - self.usePhysics = physics - - -- Make sure systems is valid - for i,s in ipairs(self.systems) do - - if s.isCppSystem then - - assert(s.init ~= nil, "C++ system object missing init property") - - else - - local err = nil - - if s.is_a == nil then - - err = "Lua table in GameState.systems is not a class (no 'is_a' method)!" - - else - - if s:is_a(LuaSystem) == false then - - err = "Lua table in GameState.systems is not derived from LuaSystem!" - - end - end - - if err then - - print(err) - print("Index " .. i .. " table:") - print_r(s) - error(err) - - end - - - assert(s.init ~= nil, "Lua system derived type is missing init") - - end - - end - - end -) - ---! @brief Initializes a state to be used. ---! @brief System initializer called once engine is set up -function GameState:init() - - -- Create entity manager - self.entityManager = EntityManager.new() - - self.guiWindow = CEGUIWindow.new(self.guiLayoutName) - - --! @brief Adds physics to this GameState - if self.usePhysics == true then - - self.physicsWorld = PhysicalWorld.new() - - end - - -- This is passed to C++ systems - self.cppData = GameStateData.new(self, Engine, self.entityManager, self.physicsWorld) - -- another name - self.wrapper = self.cppData - - assert(self.wrapper ~= nil, "GameState failed to create C++ wrapper") - - -- Init systems - for i,s in ipairs(self.systems) do - - if s.isCppSystem then - - s:init(self.wrapper) - - else - - s:init(self) - end - - end - - if self.extraInitializer ~= nil then - - self:extraInitializer() - - end - -end - - ---! @brief Must be called when this gamestate is no longer needed ---! ---! Shuts down all systems and releases the C++ data object -function GameState:shutdown() - - for i,s in ipairs(self.systems) do - - s:shutdown() - - end - - self.cppData = nil - self.physicsWorld = nil - self.entityManager = nil - self.guiWindow = nil -end - - ---! @brief Called when this gamestate is made the active one -function GameState:activate() - - self.guiWindow:show() - - -- Make this states' main window (and its children) visible - CEGUIWindow.getRootWindow():addChild(self.guiWindow) - - for i,s in ipairs(self.systems) do - - s:activate() - end - -end - ---! @brief Called when another gamestate becomes active -function GameState:deactivate() - - for i,s in ipairs(self.systems) do - - s:deactivate() - - end - - self.guiWindow:hide() - CEGUIWindow.getRootWindow():removeChild(self.guiWindow) - -end - - ---! @brief Updates game logic -function GameState:update(renderTime, logicTime) - - for i,s in ipairs(self.systems) do - --Uncomment to debug mystical crashes and other anomalies - -- print("Updating system " .. s.name) - s:update(renderTime, logicTime) - -- print("Done updating system " .. s.name) - end - - self.entityManager:processRemovals() - -end - - ---! @brief Restores saved entities from storage ---! @param storage the StorageContainer that was created with a previous call to ---! GameState:storage -function GameState:load(storage) - - local entities = storage:get("entities") - - self.entityManager:clear() - - self.entityManager:restore(entities, Engine.componentFactory) - -end - ---! @brief Saves all current entities into a StorageContainer ---! @see GameState:load ---! @returns StorageContainer -function GameState:storage() - - local entities = self.entityManager:storage(Engine.componentFactory) - - local storage = StorageContainer.new() - storage:set("entities", entities) - - return storage -end - ---! @brief Returns self.guiWindow -function GameState:rootGUIWindow() - - return self.guiWindow - -end - ---! @brief Returns an array of C++ based systems -function GameState:getCppSystems() - - local result = {} - local index = 1 - - for i,s in ipairs(self.systems) do - - if s.isCppSystem then - - result[index] = s - index = index + 1 - - end - end - - return result - -end - diff --git a/scripts/lua_engine/keymap.lua b/scripts/lua_engine/keymap.lua deleted file mode 100644 index e07bc356a06..00000000000 --- a/scripts/lua_engine/keymap.lua +++ /dev/null @@ -1,85 +0,0 @@ --- Holds the keymap - -kmp = {} - --- Microbe Editor -- - -kmp.undo = {"ctrl", "Z"} -kmp.redo = {"ctrl", "Y"} - -kmp.remove = {"R"} -kmp.newmicrobe = {"C"} - -kmp.vacuole = {"V"} -kmp.mitochondrion = {"M"} -kmp.oxytoxyvacuole = {"T"} -kmp.flagellum = {"F"} -kmp.chloroplast = {"P"} - - -kmp.togglegrid = {"G"} - -kmp.rename = {"ESCAPE"} -kmp.rename2 = {"F12"} -kmp.gotostage = {"F2"} - --- Microbe Stage -- - -kmp.forward = {"W"} -kmp.backward = {"S"} -kmp.leftward = {"A"} -kmp.rightward = {"D"} - -kmp.shootoxytoxy = {"E"} -kmp.reproduce = {"P"} - -kmp.togglemenu = {"ESCAPE"} -kmp.skipvideo = {"ESCAPE"} -kmp.gotoeditor = {"F2"} -kmp.screenshot = {"SYSRQ"} --printscreen button - -kmp.plus = {"EQUALS"} -kmp.add = {"ADD"} -kmp.minus = {"MINUS",} -kmp.subtract = {"SUBTRACT"} - --- this is the perfect kind of thing to move into C++ --- it shouldn't require anything in Lua, it'll just get a table of strings, and do comparisons -function keyCombo(combo) - -- Boolean function, used to check if key combo is pressed - - mods = {} -- holds whether each particular modifier key (left-right-agnostic) is pressed - mods.ctrl = false - mods.alt = false - mods.shift = false - - for _, key in ipairs(combo) do - if key == "ctrl" then - mods.ctrl = true - elseif key == "shift" then - mods.shift = true - elseif key == "alt" then - mods.alt = true - elseif not Engine.keyboard:wasKeyPressed(KEYCODE["KC_"..key]) then - return false - end - end - -- fail if any modkey pressed unmatches required mods - - if (Engine.keyboard:isKeyDown(KEYCODE.KC_LCONTROL) - or Engine.keyboard:isKeyDown(KEYCODE.KC_RCONTROL) - ) ~= mods.ctrl then - return false - end - if (Engine.keyboard:isKeyDown(KEYCODE.KC_LSHIFT) - or Engine.keyboard:isKeyDown(KEYCODE.KC_RSHIFT) - ) ~= mods.shift then - return false - end - if (Engine.keyboard:isKeyDown(KEYCODE.KC_LMENU) - or Engine.keyboard:isKeyDown(KEYCODE.KC_RMENU) - ) ~= mods.alt then - return false - end - return true -end diff --git a/scripts/lua_engine/lua_engine.lua b/scripts/lua_engine/lua_engine.lua deleted file mode 100644 index c780043e68f..00000000000 --- a/scripts/lua_engine/lua_engine.lua +++ /dev/null @@ -1,460 +0,0 @@ ---! @file Lua versions of functions in engine.cpp ---! ---! This is done to allow the main loop of the game to be in lua and ---! that way reduce calls from C++ to Lua. With JIT the Lua code ---! is fast enough to be the "glue" between C++ systems and Lua ---! systems and main loop - -LuaEngine = class( - - function(self) - - -- The state the engine is switching to on next frame - self.nextGameState = nil - - -- The current main GameState. Touching this directly WILL cause problems - -- (unless you are careful, but... don't do it) - self.currentGameState = nil - - -- List of all created GameStates - self.gameStates = {} - - - - -- The console object attaches itself here - self.console = nil - self.consoleGUIWindow = nil - - -- This is a table of systems that are going to be moved to prevShutdownSystems once - -- the GameState changes. So this is used to get all the systems that the current state - -- wants to timed shutdown - self.nextShutdownSystems = {} - - -- This is a table of currently running systems that need to be shutdown - self.prevShutdownSystems = {} - - end -) - ---! @brief Initializes the lua side of the engine ---! @param cppSide the engine object received from ---! c++ code -function LuaEngine:init(cppSide) - - assert(cppSide ~= nil) - - self.Engine = cppSide - - self.initialized = true - - print("LuaEngine init started") - - self.consoleGUIWindow = CEGUIWindow.new("Console") - - -- Store current state - local previousGameState = self.currentGameState - - -- Initialize states that have been created while loading all the scripts - for _,s in pairs(self.gameStates) do - - self.currentGameState = s - - s:init() - - end - - -- Restore the state - self.currentGameState = previousGameState - -end - ---! @brief Shutsdown all systems -function LuaEngine:shutdown() - - for _,s in pairs(self.gameStates) do - - s:shutdown() - - end -end - ---! @param name Unique name of the system ---! @param systems Array of systems that are in the new GameState. ---! Must be created with `table.insert(systems, s)` ---! @param physics If true creates a physics state in the GameState ---! @todo Make sure that .destroy() is called on these objects ---! @param extraInitializer Function to be ran just after the GameState ---! is initialized. The first parameter to the function is the gameState -function LuaEngine:createGameState(name, - systems, - physics, - guiLayoutName, - extraInitializer) - - assert(self.initialized ~= true, - "LuaEngine: trying to create state after init. State wouldn't be initialized!") - - if extraInitializer ~= nil then - - -- Initializer must be a function - assert(type(extraInitializer) == "function", - "extraInitializer must be a function") - - end - -- Type check everything for bad calls - assert(type(name) == "string") - assert(type(systems) == "table") - assert(type(physics) == "boolean") - assert(type(guiLayoutName) == "string") - - assert(self.gameStates[name] == nil, "Duplicate GameState name") - - local newState = GameState.new(name, systems, self, physics, - guiLayoutName, extraInitializer) - - self.gameStates[name] = newState - - return newState -end - ---! @brief Runs updates on some core systems and the current GameState -function LuaEngine:update(milliseconds) - - self.Engine:update(milliseconds) - - -- Update GameStates - - if self.nextGameState ~= nil then - - self:activateGameState(self.nextGameState) - self.nextGameState = nil - - end - - if self.currentGameState == nil then - error("currentGameState is nil") - end - - -- Update current GameState - local updateTime = milliseconds - - if self.Engine.paused then - updateTime = 0 - end - - self.currentGameState:update(milliseconds, updateTime) - - -- Update console - self.console:update() - - - -- Update any timed shutdown systems - -- Reverse iterate to safely remove items - for i = #self.prevShutdownSystems, 1, -1 do - - local delayed = self.prevShutdownSystems[i] - - local updateTime = math.min(delayed.timeLeft, milliseconds); - - - local pauseHelper = updateTime - - if self.Engine.paused then - - pauseHelper = 0 - - end - - delayed.system:update(updateTime, pauseHelper) - - delayed.timeLeft = delayed.timeLeft - updateTime - - if delayed.timeLeft <= 0 then - - -- Remove systems that had timed out - delayed.system:deactivate() - table.remove(self.prevShutdownSystems, i) - - end - end -end - - --- Timed shutdown functions - ---! @brief Keeps a system alive after being shut down for a specified amount of time ---! ---! Note that this causes update to be called for the specified duration so be careful ---! to ensure that the system is not enabled or it will get update calls twice. ---! ---! @param system ---! The system to keep updated ---! ---! @param milliseconds ---! The number of milliseconds to keep the system updated for ---! -function LuaEngine:timedSystemShutdown(system, milliseconds) - - table.insert(self.prevShutdownSystems, { timeLeft = milliseconds, ["system"] = system }) - -end - ---! @brief Returns true if system is already queued for shutdown -function LuaEngine:isSystemTimedShutdown(system) - - for i,p in ipairs(self.prevShutdownSystems) do - - if p.system == system then - return true - end - - end - - return false - -end - - ---! @brief Sets the current game state ---! ---! The game state will be activated at the beginning of the next frame. ---! ---! \a gameState must not be \c null. ---! ---! @param gameState GameState The new game state -function LuaEngine:setCurrentGameState(gameState) - - assert(gameState ~= nil, "GameState must not be null") - - self.nextGameState = gameState; - - --Make sure systems are deactivated before any potential reactivations - - for _,p in pairs(self.prevShutdownSystems) do - - p.system:deactivate() - - end - - self.prevShutdownSystems = self.nextShutdownSystems - self.nextShutdownSystems = {} - -end - - - ---! @brief Retrieves a game state ---! @param name The game state's name ---! @return The GameState with the name or nil -function LuaEngine:getGameState(name) - - return self.gameStates[name] - -end - ---! @brief Returns a system that has the potential C++ side object -function LuaEngine:gameStateFromCpp(cppObj) - - local objType = type(cppObj) - - if objType == "table" then - - -- Already a Lua type - return nil - - end - - assert(objType == "userdata") - - local cppName = cppObj.name - - for _,s in pairs(self.gameStates) do - - --if s.wrapper == cppObj then - -- name compare, this seems to work better than equality - if s.name == cppName then - - return s - - end - - end - - return nil -end - ---! @brief Returns a lua State owning cppWrapper or asserts -function LuaEngine:getLuaStateFromWrapper(cppWrapper) - - assert(cppWrapper) - assert(type(cppWrapper) == "userdata") - - local state = self:gameStateFromCpp(cppWrapper) - - if state ~= nil then - - return state - end - - assert(false, "getLuaSystemFromWrapper(cppWrapper) failed to find state with wrapper") -end - ---! @brief Transfers an entity from one gamestate to another ---! ---! @param oldEntityId ---! The id of the entity to transfer in the old entitymanager ---! ---! @param oldEntityManager ---! The old entitymanager which is currently handling the entity. EntityManager type ---! ---! @param newGameState ---! The new gamestate to transfer the entity to ---! @return The new entity id in the new gamestate -function LuaEngine:transferEntityGameState(oldEntityId, - oldEntityManager, - newGameState) - - local state = self:gameStateFromCpp(newGameState) - - if state ~= nil then - newGameState = state - end - - local newEntity -- EntityId - - assert(oldEntityId) - assert(type(oldEntityId) == "number") - local nameMapping = oldEntityManager:getNameMappingFor(oldEntityId) - - if nameMapping ~= nil then - - newEntity = newGameState.entityManager:getNamedId(nameMapping, true) - - else - newEntity = newGameState.entityManager:generateNewId() - end - - oldEntityManager:transferEntity( - oldEntityId, newEntity, newGameState.entityManager, Engine.componentFactory); - - return newEntity; -end - - - ---! @protected @brief Changes the current GameState right now. May not ---! be called during an update! -function LuaEngine:activateGameState(gameState) - - if self.currentGameState ~= nil then - - self.currentGameState:deactivate() - - end - - self.currentGameState = gameState - - if self.currentGameState ~= nil then - - gameState:activate() - - gameState:rootGUIWindow():addChild(self.consoleGUIWindow) - - self.console:registerEvents(gameState) - end - -end - - ---! @protected @brief Called from C++ side to load game states from a StorageContainer ---! @param saveGame StorageContainer with saved data -function LuaEngine:loadSavegameGameStates(saveGame) - - local previousGameState = self.currentGameState - - self:activateGameState(nil) - - local gameStatesContainer = saveGame:get("gameStates") - - for name, system in pairs(self.gameStates) do - - if gameStatesContainer:contains(name) then - - -- In case anything relies on the current game state - -- during loading, temporarily switch it - self.currentGameState = system - - system:load(gameStatesContainer:get(name)) - - else - system.entityManager:clear() - end - - end - - for _,p in pairs(self.prevShutdownSystems) do - - p.system:deactivate() - - end - - for _,p in pairs(self.nextShutdownSystems) do - - p.system:deactivate() - - end - - self.nextShutdownSystems = {} - self.prevShutdownSystems = {} - - - self.currentGameState = nil - - -- Switch gamestate - local gameStateName = saveGame:get("currentGameState") - - local gameState = self:getGameState(gameStateName) - - if gameState ~= nil then - - self:activateGameState(gameState) - - else - - self:activateGameState(previousGameState) - print("Error loading GameStates: unkown name for 'currentGameState'") - - end - -end - - ---! @protected @brief Called from C++ side to load game states from a StorageContainer ---! @param saveGame StorageContainer to be filled with saved data -function LuaEngine:saveCurrentStates(saveGame) - - saveGame:set("currentGameState", self.currentGameState.name) - - local gameStatesContainer = StorageContainer.new() - - for name, system in pairs(self.gameStates) do - - gameStatesContainer:set(name, system:storage()) - - end - - saveGame:set("gameStates", gameStatesContainer) - -end - ---! Sets the console object. Called from console.lua -function LuaEngine:registerConsoleObject(console) - - self.console = console; - -end - ---! Global LuaEngine instance -g_luaEngine = LuaEngine.new() - - diff --git a/scripts/lua_engine/manifest.txt b/scripts/lua_engine/manifest.txt deleted file mode 100644 index bb4ba29cb3a..00000000000 --- a/scripts/lua_engine/manifest.txt +++ /dev/null @@ -1,9 +0,0 @@ -system.lua - -keymap.lua - -game_state.lua - -lua_engine.lua - - diff --git a/scripts/lua_engine/system.lua b/scripts/lua_engine/system.lua deleted file mode 100644 index 06a8704b1de..00000000000 --- a/scripts/lua_engine/system.lua +++ /dev/null @@ -1,63 +0,0 @@ --- Lua System base class - -LuaSystem = class( - --! @brief Constructs a new System. Should be called from derived classes with - --! `LuaSystem.create(self)` - function(self) - - -- Sanity check that fails if obj doesn't derive from system - assert(self:is_a(LuaSystem), - "LuaSystem.construct called on table that isn't a LuaSystem") - - -- This is no longer used to determine which systems to run - self.enabled = true - - self.isLuaSystem = true - - - - end -) - --- default implementations -function LuaSystem:update(renderTime, logicTime) - - error("default LuaSystem:update called") - -end - -function LuaSystem:destroy() - - self.gameState = nil - -end - ---! Base init. Must be called from derived classes -function LuaSystem:init(name, gameState) - - assert(name ~= nil) - assert(gameState ~= nil) - - assert(type(name) == "string") - - self.name = name - self.gameState = gameState -end - - ---! Base shutdown. Does nothing. Doesn't need to be called -function LuaSystem:shutdown() - -end - --- Looks like derived systems are really bad at calling these things --- so these are now not required to be called as they do nothing - -function LuaSystem:activate() - -end - -function LuaSystem:deactivate() - -end - diff --git a/scripts/lua_notes.md b/scripts/lua_notes.md deleted file mode 100644 index 6df51a0449d..00000000000 --- a/scripts/lua_notes.md +++ /dev/null @@ -1,178 +0,0 @@ -How to debug easier -=================== - -Enable more checks ------------------- - -By default most Lua safety checks are off. To make debugging easier -you can build thrive with extra safety checks by specifying `LUA_CHECKS=ON` -when running cmake. Like this: - -```bash -cmake .. -DLUA_CHECKS=ON -``` - - -Changes with the switch to sol -============================== - - -Lua syntax changes ------------------- - -creating instances of class are like this: -`ColourValue.new(arguments)` instead of `ColourValue(arguments)`. - - -Function calls, MUST have `(` on the same line as the call. This is a syntax error: - -```lua -self.id = currentSpawnSystem:addSpawnType -( - ... -) -``` - -This is the correct syntax: - -```lua -self.id = currentSpawnSystem:addSpawnType( - ... -) -``` - - -If you are getting errors about "attempt to call a string value" -without a stack trace. Then this is most likely what you have done -wrong. - - - -### Casting from base Component - -`entity:getComponent` returns the base Component type so it is -required to be casted to a specific type like -`CompoundAbsorberComponent` to be used. For example: -`CompoundAbsorberComponent.castFrom(entity:getComponent(CompoundAbsorberComponent.TYPE_ID))` - -Or you can use the helper `getComponent("main_menu_ambience", -self.gameState, SoundSourceComponent ).autoLoop = true` - - - -Lua components are handled as ComponentWrapper inside C++ so it s -required to be unwrapped like this: -`unwrapWrappedComponent(entity:getComponent(MicrobeComponent.TYPE_ID))`. -For performance reasons it might be worth it to also move the entity -manager to Lua, but that hasn't been done yet. - - -### The .new method - -Before all Lua objects were created like this: -`OgreSceneNodeComponent()` but now you need to call the `.new` method -like this: `OgreSceneNodeComponent.new()`. Though, for convenience -some classes expose (one of) their constructors the old way. For -example the vector class: `Vector3(1, 5, 0)` and `Degree` but only the -numeric constructors. So if you want to call `Degree` constructor with -a `Radian` you will need to use `Degree.new(radianVariable)`. - - -Renames and different function signatures ------------------------------------------ - -Renamed `CollisionShape.Axis.AXIS_X` to `SHAPE_AXIS.X` -also same with Y and Z - - -`CollisionFilter.collisions` now constructs a table from the iterator -that the actual `.collisions` method returns - - -`Keyboard.KeyCode` is now global enum `KEYCODE` - - -`Ogre::Ray::intersects` now returns a tuple - -Order of multiplication matters (sometimes) -------------------------------------------- - -Now because overloaded operators are only on the user types (by -default) the complex type needs to be on the left hand side: -`direction * impulseMagnitude` is correct (where direction is a -Vector3 and impulseMagnitude is a float). This is wrong and causes an -error: `direction * impulseMagnitude` (`sol: no matching function call -takes this number of arguments and the specified types`) - - -This is actually fixed for Vector3 class so the above example works -both ways. But some other classes might miss this. If they are it is -quite easy to add, just look at how -`lua.new_usertype("Vector3", ... ` registers its -addition metamethod overloads. - - -### New calls to C++ functions taking GameState arguments - -Now the GameState object is not exposed to C++ instead there is a -wrapper that needs to be passed to C++. It is stored in -`GameState.wrapper` so now `self.entities:init(gameState)` becomes -`self.entities:init(gameState.wrapper)` - - -If you don't pass the wrapper you will get a segmentation fault. But -if you have turned on LUA_CHECKS then you will get an error message -like this: `stack index 2, expected userdata, received table` - - - -C++ notes ---------- - -C++ systems now receive a `GameStateData` object that allows them to -query stuff that Lua has setup. - - -Don't screw up by using `sol::var` when you should have used -`sol::property`, this is specially when binding lambdas or other -*property* accessors. - - -#### Warning - ->Do NOT save the return type of a function_result with auto, as in ->`auto numwoof = woof(20);`, and do NOT store it anywhere. - -From here: [safety - sol](https://sol2.readthedocs.io/en/latest/safety.html) - - - -Running with valgrind ---------------------- - -To avoid false positives LuaJIT makefile needs to be altered to enable -debug info and valgrind support mode. Plus you might need to use a -luajit valgrind suppression -file. -[Some instructions here](https://gist.github.com/deltheil/3d446d00a39cca138978) - - -GDB Debugging -------------- - -LuaJIT can provide source file information for GDB with GDB version -7+. To use this uncomment `XCFLAGS+= -DLUAJIT_USE_GDBJIT` in the -LuaJIT makefile. See `lj_gdbjit.c` for instructions how to set -breakpoints in Lua. - - - - - - - - - - - - diff --git a/scripts/main_menu/main_menu_hud.lua b/scripts/main_menu/main_menu_hud.lua deleted file mode 100644 index 2654a0376ae..00000000000 --- a/scripts/main_menu/main_menu_hud.lua +++ /dev/null @@ -1,122 +0,0 @@ --- Updates the hud with relevant information - -MainMenuHudSystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - - end -) - -function MainMenuHudSystem:init(gameState) - LuaSystem.init(self, "MainMenuHudSystem", gameState) - root = gameState.guiWindow - - local microbeButton = root:getChild("Background"): - getChild("MainMenuInteractive"):getChild("NewGameButton") - local quitButton = root:getChild("Background"): - getChild("MainMenuInteractive"):getChild("ExitGameButton") - local loadButton = root:getChild("Background"): - getChild("MainMenuInteractive"):getChild("LoadGameButton") - - microbeButton:registerEventHandler("Clicked", mainMenuMicrobeStageButtonClicked) - loadButton:registerEventHandler("Clicked", mainMenuLoadButtonClicked) - quitButton:registerEventHandler("Clicked", quitButtonClicked) - - updateLoadButton(); - - self.videoPlayer = CEGUIVideoPlayer.new("IntroPlayer") - root:addChild( self.videoPlayer) - - self.hasShownIntroVid = false - self.vidFadeoutStarted = false - self.skippedVideo = false - - -- Set version in GUI - local versionLabel = root:getChild("Background"): - getChild("MainMenuInteractive"):getChild("VersionLabel") - - versionLabel:setText("v" .. Engine.thriveVersion) - -end - -function MainMenuHudSystem:update(renderTime, logicTime) - if keyCombo(kmp.screenshot) then - Engine:screenShot("screenshot.png") - elseif keyCombo(kmp.skipvideo) then - if self.videoPlayer then - self.videoPlayer:close() - self.videoPlayer:hide() - - getComponent("gui_sounds", self.gameState, SoundSourceComponent - ):interruptPlaying() - - getComponent("main_menu_ambience", self.gameState, SoundSourceComponent - ).autoLoop = true - - self.skippedVideo = true - end - elseif keyCombo(kmp.forward) then - - end - if self.videoPlayer then - self.videoPlayer:update() - if self.videoPlayer:getCurrentTime() >= self.videoPlayer:getDuration() - 3.0 then - if not self.vidFadeoutStarted then - self.videoPlayer:playAnimation("fadeout") - self.vidFadeoutStarted = true - end - if not self.skippedVideo and self.videoPlayer:getCurrentTime() >= self.videoPlayer:getDuration() then - self.videoPlayer:hide() - - getComponent("main_menu_ambience", self.gameState, SoundSourceComponent - ).autoLoop = true - - end - end - end -end - -function MainMenuHudSystem:shutdown() - -- Necessary to avoid failed assert in ogre on exit - CEGUIVideoPlayer.destroyVideoPlayer(self.videoPlayer) -end - -function MainMenuHudSystem:activate() - updateLoadButton(); - if self.videoPlayer and not self.hasShownIntroVid then - self.videoPlayer:setVideo("intro.wmv") - self.hasShownIntroVid = true - self.videoPlayer:play() - end -end - -function updateLoadButton() - if Engine:fileExists("quick.sav") then - root:getChild("Background"):getChild("MainMenuInteractive"):getChild("LoadGameButton"):enable(); - else - root:getChild("Background"):getChild("MainMenuInteractive"):getChild("LoadGameButton"):disable(); - end -end - - -function mainMenuLoadButtonClicked() - - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - - g_luaEngine:setCurrentGameState(GameState.MICROBE) - Engine:load("quick.sav") - print("Game loaded"); -end - -function mainMenuMicrobeStageButtonClicked() - - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - - g_luaEngine:setCurrentGameState(GameState.MICROBE_TUTORIAL) -end - --- quitButtonClicked is already defined in microbe_stage_hud.lua diff --git a/scripts/main_menu/manifest.txt b/scripts/main_menu/manifest.txt deleted file mode 100644 index 40d110166c8..00000000000 --- a/scripts/main_menu/manifest.txt +++ /dev/null @@ -1,4 +0,0 @@ - -// Setup -main_menu_hud.lua -setup.lua diff --git a/scripts/main_menu/setup.lua b/scripts/main_menu/setup.lua deleted file mode 100644 index 53267cc8e9f..00000000000 --- a/scripts/main_menu/setup.lua +++ /dev/null @@ -1,71 +0,0 @@ - -local function setupCamera(gameState) - local entity = Entity.new(CAMERA_NAME .. "2", gameState.wrapper) - -- Camera - local camera = OgreCameraComponent.new("camera2") - camera.properties.nearClipDistance = 5 - camera.properties:touch() - entity:addComponent(camera) - -- Scene node - local sceneNode = OgreSceneNodeComponent.new() - entity:addComponent(sceneNode) - -- Workspace - local workspaceEntity = Entity.new(gameState.wrapper) - -- TODO: could create a workspace without shadows - local workspaceComponent = OgreWorkspaceComponent.new("thrive_default") - workspaceComponent.properties.cameraEntity = entity - workspaceComponent.properties.position = 0 - workspaceComponent.properties:touch() - workspaceEntity:addComponent(workspaceComponent) -end - -local function setupSound(gameState) - -- Background music - local ambientEntity = Entity.new("main_menu_ambience", gameState.wrapper) - local soundSource = SoundSourceComponent.new() - soundSource.ambientSoundSource = true - soundSource.autoLoop = false - soundSource.volumeMultiplier = 0.15 - ambientEntity:addComponent(soundSource) - soundSource:addSound("main-menu-theme-1", "main-menu-theme-1.ogg") - soundSource:addSound("main-menu-theme-2", "main-menu-theme-2.ogg") - -- Gui effects - local guiSoundEntity = Entity.new("gui_sounds", gameState.wrapper) - soundSource = SoundSourceComponent.new() - soundSource.ambientSoundSource = true - soundSource.autoLoop = false - soundSource.volumeMultiplier = 1.0 - guiSoundEntity:addComponent(soundSource) - -- Sound - soundSource:addSound("button-hover-click", "soundeffects/gui/button-hover-click.ogg") -end - -local function createMainMenu(name) - - return g_luaEngine:createGameState( - name, - { - -- Graphics - OgreAddSceneNodeSystem.new(), - OgreUpdateSceneNodeSystem.new(), - OgreCameraSystem.new(), - MainMenuHudSystem.new(), - OgreWorkspaceSystem.new(), - OgreRemoveSceneNodeSystem.new(), - RenderSystem.new(), - -- Other - SoundSourceSystem.new(), - }, - -- No physics - false, - "MainMenu", - function(gameState) - setupCamera(gameState) - setupSound(gameState) - end - ) -end - -GameState.MAIN_MENU = createMainMenu("main_menu") - -g_luaEngine:setCurrentGameState(GameState.MAIN_MENU) diff --git a/scripts/manifest.txt b/scripts/manifest.txt deleted file mode 100644 index e758eec5a3e..00000000000 --- a/scripts/manifest.txt +++ /dev/null @@ -1,21 +0,0 @@ -// utilities and definitions -util.lua -colours.lua -class.lua -constants.lua - -// engine stuff like gamestates -lua_engine - -main_menu -microbe_stage -microbe_stage_tutorial -microbe_editor -//sandbox - -console.lua -console_commands.lua - -// main loop is defined here -game.lua - diff --git a/scripts/microbe_editor/manifest.txt b/scripts/microbe_editor/manifest.txt deleted file mode 100644 index a09facb6266..00000000000 --- a/scripts/microbe_editor/manifest.txt +++ /dev/null @@ -1,7 +0,0 @@ - -microbe_editor_hud.lua -microbe_editor.lua - - -// Setup -setup.lua diff --git a/scripts/microbe_editor/microbe_editor.as b/scripts/microbe_editor/microbe_editor.as new file mode 100644 index 00000000000..e7ff44602ef --- /dev/null +++ b/scripts/microbe_editor/microbe_editor.as @@ -0,0 +1,592 @@ +#include "microbe_editor_hud.as" +/* +//////////////////////////////////////////////////////////////////////////////// +// MicrobeEditor +// +// Contains the functionality associated with creating and augmenting microbes +// See http://www.redblobgames.com/grids/hexagons/ for mathematical basis of hex related code. +//////////////////////////////////////////////////////////////////////////////// +*/ + +class MicrobeEditor{ + MicrobeEditor(MicrobeEditorHudSystem@ hud){ + organelleCount = 0; + @hudSystem = hud; + gridVisible = true; + //Perhaps this should be turned into a constant? + mutationPoints = 100; + //TODO.Check to make certain this works + // placementFunctions = {["nucleus"] = MicrobeEditor::createNewMicrobe(), + // ["flagellum"] = MicrobeEditor::addOrganelle(), + // ["cytoplasm"] = MicrobeEditor::addOrganelle(), + // ["mitochondrion"] = MicrobeEditor::addOrganelle(), + // ["chloroplast"] = MicrobeEditor::addOrganelle(), + // ["oxytoxy"] = MicrobeEditor::addOrganelle(), + // ["vacuole"] = MicrobeEditor::addOrganelle(), + // ["remove"] = MicrobeEditor::removeOrganelle()}; + actionIndex = 0; + organelleRot = 0; + symmetry = 0; + } + + //TODO.find new equivalents of all these classes + void init(){ + /*auto ent = Entity(gameState.wrapper) + auto sceneNode = OgreSceneNodeComponent() + sceneNode.planeTexture = "EditorGridMaterial" + ent.addComponent(sceneNode) + sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, 1) + sceneNode.transform.touch() + + gridSceneNode = sceneNode*/ + } + + //TODO: make certain all this works + void activate(){ + // //TODO: find new equivalent of this. + // auto creatureState = g_luaEngine.getLuaStateFromWrapper( + // Engine.playerData().activeCreatureGamestate()); + + // if (creatureState.name == CellStageWorld@.MICROBE.name || + // creatureState.name == CellStageWorld@.MICROBE_TUTORIAL.name){ + + // //TODO: check to make certain this class is still valid + // auto microbeStageMicrobe = Entity("player", CellStageWorld@.MICROBE.wrapper); + + // //TODO: find new equivalent of this + // nextMicrobeEntity = Entity( + // g_luaEngine.transferEntityGameState(microbeStageMicrobe.id, + // creatureState.entityManager, + // CellStageWorld@.MICROBE_EDITOR), + // CellStageWorld@.MICROBE_EDITOR.wrapper); + + // //Transfer the compounds + // MicrobeSystem.initializeMicrobe(nextMicrobeEntity, true); + // MicrobeSystem.transferCompounds(microbeStageMicrobe, nextMicrobeEntity); + + // nextMicrobeEntity.stealName("working_microbe"); + // Engine.playerData().setBool("edited_microbe", true); + // Engine.playerData().setActiveCreature(nextMicrobeEntity.id, + // CellStageWorld@.MICROBE_EDITOR.wrapper); + // } + + + // mutationPoints = 100; + // dictionary actionHistory = {}; // where all user actions will be registered + // actionIndex = 0; // marks the last action that has been done (not undone, but possibly redone), is 0 if there is none + // //TODO.fix this for loop + // /*for(_, cytoplasm in pairs(occupiedHexes)){ + // cytoplasm.destroy() + // }*/ + + // currentMicrobeEntity = nextMicrobeEntity; + // MicrobeSystem.initializeMicrobe(nextMicrobeEntity, true); + // auto microbeComponent = getComponent(currentMicrobeEntity, MicrobeComponent); + // auto sceneNodeComponent = getComponent(currentMicrobeEntity, OgreSceneNodeComponent); + // sceneNodeComponent.transform.orientation = Quaternion( + // Radian(Degree(0)), Vector3(0, 0, 1)); //Orientation + // sceneNodeComponent.transform.position = Vector3(0, 0, 0); + // sceneNodeComponent.transform.touch(); + + // /* TODO: fix this for loop as well + // for(_, organelle in pairs(microbeComponent.organelles)){ + // for(s, hex in pairs(organelle._hexes)){ + // this.createHexComponent(hex.q + organelle.position.q, hex.r + organelle.position.r) + // } + // }*/ + } + + void update(int logicTime){ + // //TODO: rewrite getMouseHex() + // //local q, r = this.getMouseHex() + + // if (symmetry == 0){ + // renderHighlightedOrganelle(1, q, r, organelleRot); + // } + // else if (symmetry == 1){ + // renderHighlightedOrganelle(1, q, r, organelleRot); + // renderHighlightedOrganelle(2, -1*q, r+q, 360+(-1*organelleRot)); + // } + // else if (symmetry == 2){ + // renderHighlightedOrganelle(1, q, r, organelleRot); + // renderHighlightedOrganelle(2, -1*q, r+q, 360+(-1*organelleRot)); + // renderHighlightedOrganelle(3, -1*q, -1*r, (organelleRot+180) % 360); + // renderHighlightedOrganelle(4, q, -1*(r+q), 540+(-1*organelleRot) % 360); + // } + // else if (symmetry == 3){ + // renderHighlightedOrganelle(1, q, r, organelleRot); + // renderHighlightedOrganelle(2, -1*r, r+q, (organelleRot+60) % 360); + // renderHighlightedOrganelle(3, -1*(r+q), q, (organelleRot+120) % 360); + // renderHighlightedOrganelle(4, -1*q, -1*r, (organelleRot+180) % 360); + // renderHighlightedOrganelle(5, r, -1*(r+q), (organelleRot+240) % 360); + // renderHighlightedOrganelle(6, r+q, -1*q, (organelleRot+300) % 360); + // } + + // hudSystem.updateMutationPoints(); + } + + // void _addOrganelle(Organelle organelle, double q, double r, int rotation){ + // enqueueAction({ + // cost = organelleTable[organelle.name].mpCost, + // redo = function(); + // sceneNodeComponent = getComponent(currentMicrobeEntity, OgreSceneNodeComponent); + // /*for(_, hex in pairs(organelle._hexes)){ + // // Check if there is cytoplasm under this organelle. + // auto cytoplasm = MicrobeSystem.getOrganelleAt(this.currentMicrobeEntity, hex.q + q, hex.r + r) + // if(cytoplasm){ + // if(cytoplasm.name == "cytoplasm"){ + // MicrobeSystem.removeOrganelle(this.currentMicrobeEntity, hex.q + q, hex.r + r) + // sceneNodeComponent.transform.touch() + // this.organelleCount = this.organelleCount - 1 + // auto s = encodeAxial(hex.q + q, hex.r + r) + // this.occupiedHexes[s].destroy() + // } + // } + // createHexComponent(hex.q + q, hex.r + r) + // }*/ + // MicrobeSystem.addOrganelle(currentMicrobeEntity, q, r, rotation, organelle); + // organelleCount = organelleCount + 1; + // undo = function(); + // sceneNodeComponent = getComponent(currentMicrobeEntity, OgreSceneNodeComponent); + // MicrobeSystem.removeOrganelle(currentMicrobeEntity, q, r); + // sceneNodeComponent.transform.touch(); + // organelleCount = organelleCount - 1; + // /*for(_, hex in pairs(organelle._hexes)){ + // local x, y = axialToCartesian(hex.q + q, hex.r + r) + // auto s = encodeAxial(hex.q + q, hex.r + r) + // this.occupiedHexes[s].destroy() + // }*/ + // }) + // } + + + // void addNucleus(){ + // auto nucleusOrganelle = OrganelleFactory.makeOrganelle({["name"]="nucleus", ["q"]=0, ["r"]=0, ["rotation"]=0}); + // MicrobeSystem.addOrganelle(currentMicrobeEntity, 0, 0, 0, nucleusOrganelle); + // } + + // void addOrganelle(organelleType){ + // auto q; + // auto r; + // getMouseHex(q, r); + + // if (symmetry == 0){ + // auto organelle = isValidPlacement(organelleType, q, r, organelleRot); + + // if (organelle){ + // if (organelleTable[organelle.name].mpCost > mutationPoints){ + // return; + // } + // _addOrganelle(organelle, q, r, organelleRot); + // } + // } + // else if (symmetry == 1){ + // //Makes sure that the organelle doesn't overlap on the existing ones. + // auto organelle = isValidPlacement(organelleType, q, r, organelleRot); + // if (q != -1 * q || r != r + q){ //If two organelles aren't overlapping + // auto organelle2 = isValidPlacement(organelleType, -1 * q, r + q, 360 + (-1 * organelleRot)); + + // //If the organelles were successfully created and have enough MP... + // if (organelle && organelle2 && organelleTable[organelle.name].mpCost*2 <= mutationPoints){ + // //Add the organelles to the microbe. + // _addOrganelle(organelle, q, r, organelleRot); + // _addOrganelle(organelle2, -1*q, r+q, 360+(-1*organelleRot)); + // } + // } + // else{ + // if (organelle && organelleTable[organelle.name].mpCost <= mutationPoints){ + // //Add a organelle to the microbe. + // _addOrganelle(organelle, q, r, organelleRot); + // } + // } + // } + // else if (symmetry == 2){ + // auto organelle = isValidPlacement(organelleType, q, r, organelleRot); + // if (q != -1 * q || r != r + q){ //If two organelles aren't overlapping, none are + // auto organelle2 = isValidPlacement(organelleType, -1*q, r+q, 360+(-1*organelleRot)); + // auto organelle3 = isValidPlacement(organelleType, -1*q, -1*r, (organelleRot+180) % 360); + // auto organelle4 = isValidPlacement(organelleType, q, -1*(r+q), (540+(-1*organelleRot)) % 360); + + // if (organelle && organelle2 && organelle3 && organelle4 && organelleTable[organelle.name].mpCost*4 <= mutationPoints){ + // _addOrganelle(organelle, q, r, organelleRot); + // _addOrganelle(organelle2, -1*q, r+q, 360+(-1*organelleRot)); + // _addOrganelle(organelle3, -1*q, -1*r, (organelleRot+180) % 360); + // _addOrganelle(organelle4, q, -1*(r+q), (540+(-1*organelleRot)) % 360); + // } + // } else{ + // if (organelle && organelleTable[organelle.name].mpCost <= mutationPoints){ + // _addOrganelle(organelle, q, r, organelleRot); + // } + // } + // } + // else if (symmetry == 3){ + // auto organelle = isValidPlacement(organelleType, q, r, organelleRot); + // if (q != -1 * r || r != r + q){ //If two organelles aren't overlapping, none are + // auto organelle2 = isValidPlacement(organelleType, -1*r, r+q, (organelleRot+60) % 360); + // auto organelle3 = isValidPlacement(organelleType, -1*(r+q), q, (organelleRot+120) % 360); + // auto organelle4 = isValidPlacement(organelleType, -1*q, -1*r, (organelleRot+180) % 360); + // auto organelle5 = isValidPlacement(organelleType, r, -1*(r+q), (organelleRot+240) % 360); + // auto organelle6 = isValidPlacement(organelleType, r+q, -1*q, (organelleRot+300) % 360); + + // if (organelle && organelle2 && organelle3 && organelle4 && organelle5 && organelle6 && organelleTable[organelle.name].mpCost*6 <= mutationPoints){ + // _addOrganelle(organelle, q, r, organelleRot); + // _addOrganelle(organelle2, -1*r, r+q, (organelleRot+60) % 360); + // _addOrganelle(organelle3, -1*(r+q), q, (organelleRot+120) % 360); + // _addOrganelle(organelle4, -1*q, -1*r, (organelleRot+180) % 360); + // _addOrganelle(organelle5, r, -1*(r+q), (organelleRot+240) % 360); + // _addOrganelle(organelle6, r+q, -1*q, (organelleRot+300) % 360); + // } + // } else{ + // if (organelle && organelleTable[organelle.name].mpCost <= mutationPoints){ + // _addOrganelle(organelle, q, r, organelleRot); + // } + // } + // } + // } + + // //TODO.find new equivalents of all these classes + // void createHexComponent(double q, double r){ + // Float3 axialToCartesian(q, r); + // int64_t s = encodeAxial(q, r); + // //occupiedHexes[s] = Entity(g_luaEngine.currentGameState.wrapper) + // //auto sceneNode = OgreSceneNodeComponent() + // //sceneNode.transform.position = Vector3(x, y, 0) + // //sceneNode.transform.touch() + // //sceneNode.meshName = "hex.mesh" + // //sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) + // //this.occupiedHexes[s].addComponent(sceneNode) + // //this.occupiedHexes[s].setVolatile(true) + // } + + // void createNewMicrobe(){ + // // dictionary action = { + // // redo = function() + // // organelleCount = 0 + // // atuo microbeComponent = getComponent(this.currentMicrobeEntity, MicrobeComponent) + // // speciesName = microbeComponent.speciesName + // // if (currentMicrobeEntity != null){ + // // currentMicrobeEntity.destroy(); + // // } + // // /*for(_, cytoplasm in pairs(this.occupiedHexes)){ + // // cytoplasm.destroy() + // // }*/ + + // // currentMicrobeEntity = MicrobeSystem.createMicrobeEntity(null, false, 'Editor_Microbe', true); + // // microbeComponent = getComponent(currentMicrobeEntity, MicrobeComponent); + // // auto sceneNodeComponent = getComponent(currentMicrobeEntity, OgreSceneNodeComponent); + // // currentMicrobeEntity.stealName("working_microbe"); + // // sceneNodeComponent.transform.touch(); + // // microbeComponent.speciesName = speciesName; + // // addNucleus(); + // // /*for(_, organelle in pairs(microbeComponent.organelles)){ + // // for(s, hex in pairs(organelle._hexes)){ + // // this.createHexComponent(hex.q + organelle.position.q, hex.r + organelle.position.r) + // // } + // // }*/ + // // mutationPoints = 100; + // // activeActionName = "cytoplasm"; + // // Engine.playerData().setActiveCreature(this.currentMicrobeEntity.id, GameState.MICROBE_EDITOR.wrapper) + // // } + // // } + + // if (currentMicrobeEntity != null){ + // //that there has already been a microbe in the editor suggests that it was a player action, so it's prepared and filed in for un/redo + // dictionary organelleStorage = {} + // auto previousOrganelleCount = organelleCount; + // auto previousMP = mutationPoints; + // auto currentMicrobeComponent = getComponent(currentMicrobeEntity, MicrobeComponent); + // /*for(position,organelle in pairs(currentMicrobeComponent.organelles)){ + // organelleStorage[position] = organelle.storage() + // }*/ + + // // action.undo = function(); + // // auto microbeComponent = getComponent(currentMicrobeEntity, MicrobeComponent); + + // // string speciesName = microbeComponent.speciesName + // // currentMicrobeEntity.destroy() //remove the "new" entity that has replaced the previous one + // // currentMicrobeEntity = MicrobeSystem.createMicrobeEntity(null, false, 'Editor_Microbe', true); + + // // microbeComponent = getComponent(currentMicrobeEntity, MicrobeComponent); + // // auto sceneNodeComponent = getComponent(currentMicrobeEntity, OgreSceneNodeComponent); + + // // currentMicrobeEntity.stealName("working_microbe"); + // // sceneNodeComponent.transform.orientation = Quaternion(Radian(0), Vector3(0, 0, 1)); //Orientation + // // sceneNodeComponent.transform.touch(); + // // microbeComponent.speciesName = speciesName; + // // /*for(position,storage in pairs(organelleStorage)){ + // // local q, r = decodeAxial(position) + // // MicrobeSystem.addOrganelle(this.currentMicrobeEntity, storage.get("q", 0), storage.get("r", 0), storage.get("rotation", 0), Organelle.loadOrganelle(storage)) + // // } + // // for(_, cytoplasm in pairs(this.occupiedHexes)){ + // // cytoplasm.destroy() + // // } + // // for(_, organelle in pairs(microbeComponent.organelles)){ + // // for(s, hex in pairs(organelle._hexes)){ + // // this.createHexComponent(hex.q + organelle.position.q, hex.r + organelle.position.r) + // // } + // // }*/ + // // //no need to add the nucleus manually - it's alreary included in the organelleStorage + // // mutationPoints = previousMP; + // // organelleCount = previousOrganelleCount; + // // Engine.playerData().setActiveCreature(this.currentMicrobeEntity.id, GameState.MICROBE_EDITOR.wrapper) + // // } + // enqueueAction(action); + // } else{ + // //if there's no microbe yet, it can be safely assumed that this is a generated default microbe when opening the editor for the first time, so it's not an action that should be put into the un/redo-feature + // action.redo(); + // } + // } + + + // // Instead of executing a command, put it in a table with a redo() and undo() void to make it use the Undo-/Redo-Feature.{ + // // Enqueuing it will execute it automatically, so you don't have to write things twice. + // // The cost of the action can also be incorporated into this by making it a member of the parameter table. It will be used automatically. + // void enqueueAction(action){ + // if (!(action.cost || takeMutationPoints(action.cost)){ + // while (actionHistory > actionIndex){ + // table.remove(this.actionHistory); + // } + // hudSystem.undoButton.enable(); + // hudSystem.redoButton.disable(); + // action.redo(); + // table.insert(actionHistory, action); + // actionIndex = actionIndex + 1; + // } + // } + + // // void getMouseHex(auto out qr, auto out rr){ + // // auto mousePosition = Engine.mouse.normalizedPosition(); + // // //Get the position of the cursor in the plane that the microbes is floating in + // // auto rayPoint = getComponent(CAMERA_NAME .. "3", g_luaEngine.currentGameState, + // // OgreCameraComponent + // // ).getCameraToViewportRay(mousePosition.x, mousePosition.y).getPoint(0); + + // // //Convert to the hex the cursor is currently located over. + // // auto q; + // // auto r; + // // //local q, r = cartesianToAxial(rayPoint.x, -1*rayPoint.y) //Negating X to compensate for the fact that we are looking at the opposite side of the normal coordinate system + // // //local qr, rr = cubeToAxial(cubeHexRound(axialToCube(q, r))) //This requires a conversion to hex cube coordinates and back for proper rounding. + // // //print(qr, rr) + // // //return qr, rr + // // } + + + // auto isValidPlacement(auto organelleType, double q, double r, auto rotation){ + // dictionary data = {["name"]=organelleType, ["q"]=q, ["r"]=r, ["rotation"]=rotation} + // auto newOrganelle = OrganelleFactory.makeOrganelle(data) + // bool empty = true + // bool touching = false; + // /*for (s, hex in pairs(OrganelleFactory.checkSize(data))){ + // auto organelle = MicrobeSystem.getOrganelleAt(currentMicrobeEntity, hex.q + q, hex.r + r); + // if (organelle){ + // if (organelle.name != "cytoplasm"){ + // empty = false ; + // } + // } + // if (surroundsOrganelle(hex.q + q, hex.r + r)){ + // touching = true; + // } + // }*/ + + // if (empty && touching){ + // newOrganelle.rotation = data.rotation; + // return newOrganelle; + // } + // else { + // return null; + // } + // } + + // void loadMicrobe(auto entityId){ + // organelleCount = 0; + // if (currentMicrobeEntity != null){ + // currentMicrobeEntity.destroy(); + // } + // currentMicrobeEntity = Entity(entityId, g_luaEngine.currentGameState.wrapper); + // MicrobeSystem.initializeMicrobe(currentMicrobeEntity, true); + // currentMicrobeEntity.stealName("working_microbe"); + // auto sceneNodeComponent = getComponent(currentMicrobeEntity, OgreSceneNodeComponent); + // sceneNodeComponent.transform.orientation = Quaternion(Radian(Degree(0)), + // Vector3(0, 0, 1)); //Orientation + // sceneNodeComponent.transform.touch(); + // Engine.playerData().setActiveCreature(entityId, GameState.MICROBE_EDITOR); + // mutationPoints = 0; + // //resetting the action history - it should not become entangled with the local file system + // actionHistory = {}; + // actionIndex = 0; + // } + + // void redo(){ + // if (actionIndex < actionHistory){ + // actionIndex = actionIndex + 1; + // auto action = actionHistory[actionIndex]; + // action.redo(); + // if (action.cost){ + // mutationPoints = mutationPoints - action.cost; + // } + // } + // //nothing left to redo? disable redo + // if (actionIndex >= actionHistory){ + // hudSystem.redoButton.disable(); + // } + // //upon redoing, undoing is possible + // hudSystem.undoButton.enable(); + // } + + // void removeOrganelle(){ + // auto q, r; + // getMouseHex(q, r); + // removeOrganelleAt(q,r); + // } + + // void removeOrganelleAt(double q, double r){ + // auto organelle = MicrobeSystem.getOrganelleAt(currentMicrobeEntity, q, r); + // if (!(organelle == null || organelle.name == "nucleus"){ //Don't remove nucleus + // if (organelle){ + // /*for(_, hex in pairs(organelle._hexes)){ + // auto s = encodeAxial(hex.q + organelle.position.q, hex.r + organelle.position.r) + // occupiedHexes[s].destroy() + // }*/ + // auto storage = organelle.storage(); + // enqueueAction({ + // cost = 10, + // redo = function() + // MicrobeSystem.removeOrganelle(this.currentMicrobeEntity, storage.get("q", 0), storage.get("r", 0)) + // auto sceneNodeComponent = getComponent(this.currentMicrobeEntity, OgreSceneNodeComponent) + // sceneNodeComponent.transform.touch() + // organelleCount = organelleCount - 1; + // /*for(_, cytoplasm in pairs(organelle._hexes)){ + // auto s = encodeAxial(cytoplasm.q + storage.get("q", 0), cytoplasm.r + storage.get("r", 0)) + // occupiedHexes[s].destroy() + // }*/ + // }, + // undo = function() + // auto organelle = Organelle.loadOrganelle(storage) + // MicrobeSystem.addOrganelle(currentMicrobeEntity, storage.get("q", 0), storage.get("r", 0), storage.get("rotation", 0), organelle); + // /*for(_, hex in pairs(organelle._hexes)){ + // createHexComponent(hex.q + storage.get("q", 0), hex.r + storage.get("r", 0)) + // }*/ + // organelleCount = organelleCount + 1; + // } + // }) + // } + // } + // } + + // //The first parameter states which sceneNodes to use, starting with "start" and going up 6. + // void renderHighlightedOrganelle(int start, double q, double r, auto rotation){ + // //Render the hex under the cursor + // dictionary sceneNode = {}; + // //TODO: find new equivalents + // sceneNode[1] = getComponent(hudSystem.hoverOrganelle[start], OgreSceneNodeComponent); + // for (int i = 2; i < 8; i++){ + // sceneNode[i] = getComponent(hudSystem.hoverHex[i-1+(start-1)*7], + // OgreSceneNodeComponent); + // } + + // if (activeActionName){ + // dictionary oldData = {["name"]=this.activeActionName, + // ["q"]=-q, + // ["r"]=-r, + // ["rotation"]=(180+rotation) % 360}; + // auto hexes = OrganelleFactory.checkSize(oldData); + // auto colour = ColourValue(2, 0, 0, 0.4); + // bool touching = false; + // for(_, hex in ipairs(hexes)){ + // if(this.surroundsOrganelle(-hex.q + q, -hex.r + r)){ + // colour = ColourValue(0, 2, 0, 0.4) + // } + // } + // for(_, hex in ipairs(hexes)){ + // auto organelle = MicrobeSystem.getOrganelleAt(this.currentMicrobeEntity, -hex.q + q, -hex.r + r) + // if(organelle){ + // if(organelle.name ~= "cytoplasm"){ + // colour = ColourValue(2, 0, 0, 0.4) + // } + // } + // } + // if (CEGUIWindow.getWindowUnderMouse().getName() == 'root'){ + + // dictionary newData = { + // ["name"]=activeActionName, + // ["q"]=-q, + // ["r"]=-r, + // ["sceneNode"]=sceneNode, + // ["rotation"]=(180+rotation) % 360, + // ["colour"]=colour + // }; + + // OrganelleFactory.renderOrganelles(newData) + // for (int i = 1; i < 8; i++){ + // sceneNode[i].transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE); //Vector3(1,1,1) + // sceneNode[i].transform.touch(); + // } + // } + // } + // } + + // //checks whether the hex at q, r has an organelle in its surroundeing hexes. + // auto surroundsOrganelle(double q, double r){ + // return (MicrobeSystem.getOrganelleAt(currentMicrobeEntity, q + 0, r - 1) || + // MicrobeSystem.getOrganelleAt(currentMicrobeEntity, q + 1, r - 1) || + // MicrobeSystem.getOrganelleAt(currentMicrobeEntity, q + 1, r + 0) || + // MicrobeSystem.getOrganelleAt(currentMicrobeEntity, q + 0, r + 1) || + // MicrobeSystem.getOrganelleAt(currentMicrobeEntity, q - 1, r + 1) || + // MicrobeSystem.getOrganelleAt(currentMicrobeEntity, q - 1, r + 0)); + // } + + // void setActiveAction(actionName){ + // activeActionName = actionName; + // } + + // void performLocationAction(){ + // if (activeActionName){ + // auto func = placementFunctions[activeActionName]; + // func(this, activeActionName); + // } + // } + + // bool takeMutationPoints(int amount){ + // if (amount <= mutationPoints){ + // mutationPoints = mutationPoints - amount; + // return true; + // } + // else{ + // return false; + // } + // } + + // void undo(){ + // if (actionIndex > 0){ + // auto action = actionHistory[actionIndex]; + // action.undo(); + // if (action.cost){ + // mutationPoints = mutationPoints + action.cost; + // } + // actionIndex = actionIndex - 1; + // } + // //nothing left to undo? disable undo + // if (actionIndex <= 0){ + // hudSystem.undoButton.disable(); + // } + // //upon undoing, redoing is possible + // hudSystem.redoButton.enable(); + // } + + // private auto actionHistory; + private int actionIndex; + // private auto activeActionName; + // private auto currentMicrobeEntity; + // private auto gridSceneNode; + private bool gridVisible; + private MicrobeEditorHudSystem@ hudSystem; + private int mutationPoints; + // private auto nextMicrobeEntity; + // private dictionary occupiedHexes; + private int organelleCount; + private int organelleRot; + // private dictionary placementFunctions; + //0 is no symmetry, 1 is x-axis symmetry, 2 is 4-way symmetry, and 3 is 6-way symmetry. + // TODO: change to enum + private int symmetry; +}; diff --git a/scripts/microbe_editor/microbe_editor.levgm b/scripts/microbe_editor/microbe_editor.levgm new file mode 100644 index 00000000000..78a484b8266 --- /dev/null +++ b/scripts/microbe_editor/microbe_editor.levgm @@ -0,0 +1,22 @@ +// This module includes all the editor scripts +// And some of the normal microbe stage scripts (these common things +// should be in a separate module that could be included) + + +// This isn't used for anything, increase if you want +Version = 1; + +o GameModule "microbe_editor"{ + t sourcefiles{ + // It is possible for these files to also include more stuff, but maybe it is clearer + // if everything is also listed here + setup.as + microbe_editor.as + microbe_editor_hud.as + + // TODO: move these microbe_stage included files to another module + } + + l properties{ + } +} diff --git a/scripts/microbe_editor/microbe_editor.lua b/scripts/microbe_editor/microbe_editor.lua deleted file mode 100644 index 8339cce6e81..00000000000 --- a/scripts/microbe_editor/microbe_editor.lua +++ /dev/null @@ -1,547 +0,0 @@ --------------------------------------------------------------------------------- --- MicrobeEditor --- --- Contains the functionality associated with creating and augmenting microbes --- See http://www.redblobgames.com/grids/hexagons/ for mathematical basis of hex related code. --------------------------------------------------------------------------------- -MicrobeEditor = class( - function(self, hudSystem) - self.currentMicrobeEntity = nil - self.organelleCount = 0 - self.activeActionName = nil - self.hudSystem = hudSystem - self.nextMicrobeEntity = nil - self.gridSceneNode = nil - self.gridVisible = true - self.mutationPoints = 50 - self.placementFunctions = {["nucleus"] = MicrobeEditor.createNewMicrobe, - ["flagellum"] = MicrobeEditor.addOrganelle, - ["cytoplasm"] = MicrobeEditor.addOrganelle, - ["mitochondrion"] = MicrobeEditor.addOrganelle, - ["chloroplast"] = MicrobeEditor.addOrganelle, - ["oxytoxy"] = MicrobeEditor.addOrganelle, - ["vacuole"] = MicrobeEditor.addOrganelle, - ["remove"] = MicrobeEditor.removeOrganelle} - self.actionHistory = nil - self.actionIndex = 0 - self.organelleRot = 0 - self.occupiedHexes = {} - -- 0 is no symmetry, 1 is x-axis symmetry, 2 is 4-way symmetry, and 3 is 6-way symmetry. - self.symmetry = 0 - end -) - -function MicrobeEditor:createHexComponent(q, r) - local x, y = axialToCartesian(q, r) - local s = encodeAxial(q, r) - self.occupiedHexes[s] = Entity.new(g_luaEngine.currentGameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.transform.position = Vector3(x, y, 0) - sceneNode.transform:touch() - sceneNode.meshName = "hex.mesh" - sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) - self.occupiedHexes[s]:addComponent(sceneNode) - self.occupiedHexes[s]:setVolatile(true) -end - --- checks whether the hex at q, r has an organelle in its surroundeing hexes. -function MicrobeEditor:surroundsOrganelle(q, r) - return MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, q + 0, r - 1) or - MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, q + 1, r - 1) or - MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, q + 1, r + 0) or - MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, q + 0, r + 1) or - MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, q - 1, r + 1) or - MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, q - 1, r + 0) -end - -function MicrobeEditor:init(gameState) - ent = Entity.new(gameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.planeTexture = "EditorGridMaterial" - ent:addComponent(sceneNode) - sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, 1) - sceneNode.transform:touch() - - self.gridSceneNode = sceneNode -end - -function MicrobeEditor:activate() - local creatureState = g_luaEngine:getLuaStateFromWrapper( - Engine:playerData():activeCreatureGamestate()) - - if creatureState.name == GameState.MICROBE.name or - creatureState.name == GameState.MICROBE_TUTORIAL.name then - - microbeStageMicrobe = Entity.new("player", GameState.MICROBE.wrapper) - - self.nextMicrobeEntity = Entity.new( - g_luaEngine:transferEntityGameState(microbeStageMicrobe.id, - creatureState.entityManager, - GameState.MICROBE_EDITOR), - GameState.MICROBE_EDITOR.wrapper) - - -- Transfer the compounds - MicrobeSystem.initializeMicrobe(self.nextMicrobeEntity, true) - MicrobeSystem.transferCompounds(microbeStageMicrobe, self.nextMicrobeEntity) - - self.nextMicrobeEntity:stealName("working_microbe") - Engine:playerData():setBool("edited_microbe", true) - Engine:playerData():setActiveCreature(self.nextMicrobeEntity.id, - GameState.MICROBE_EDITOR.wrapper) - end - - - self.mutationPoints = 50 - self.actionHistory = {} -- where all user actions will be registered - self.actionIndex = 0 -- marks the last action that has been done (not undone, but possibly redone), is 0 if there is none - for _, cytoplasm in pairs(self.occupiedHexes) do - cytoplasm:destroy() - end - - self.currentMicrobeEntity = self.nextMicrobeEntity - MicrobeSystem.initializeMicrobe(self.nextMicrobeEntity, true) - local microbeComponent = getComponent(self.currentMicrobeEntity, MicrobeComponent) - local sceneNodeComponent = getComponent(self.currentMicrobeEntity, OgreSceneNodeComponent) - sceneNodeComponent.transform.orientation = Quaternion.new( - Radian.new(Degree(0)), Vector3(0, 0, 1))-- Orientation - sceneNodeComponent.transform.position = Vector3(0, 0, 0) - sceneNodeComponent.transform:touch() - - for _, organelle in pairs(microbeComponent.organelles) do - for s, hex in pairs(organelle._hexes) do - self:createHexComponent(hex.q + organelle.position.q, hex.r + organelle.position.r) - end - end -end - -function MicrobeEditor:update(renderTime, logicTime) - local q, r = self:getMouseHex() - - if self.symmetry == 0 then - self:renderHighlightedOrganelle(1, q, r, self.organelleRot) - elseif self.symmetry == 1 then - self:renderHighlightedOrganelle(1, q, r, self.organelleRot) - self:renderHighlightedOrganelle(2, -1*q, r+q, 360+(-1*self.organelleRot)) - elseif self.symmetry == 2 then - self:renderHighlightedOrganelle(1, q, r, self.organelleRot) - self:renderHighlightedOrganelle(2, -1*q, r+q, 360+(-1*self.organelleRot)) - self:renderHighlightedOrganelle(3, -1*q, -1*r, (self.organelleRot+180) % 360) - self:renderHighlightedOrganelle(4, q, -1*(r+q), 540+(-1*self.organelleRot) % 360) - elseif self.symmetry == 3 then - self:renderHighlightedOrganelle(1, q, r, self.organelleRot) - self:renderHighlightedOrganelle(2, -1*r, r+q, (self.organelleRot+60) % 360) - self:renderHighlightedOrganelle(3, -1*(r+q), q, (self.organelleRot+120) % 360) - self:renderHighlightedOrganelle(4, -1*q, -1*r, (self.organelleRot+180) % 360) - self:renderHighlightedOrganelle(5, r, -1*(r+q), (self.organelleRot+240) % 360) - self:renderHighlightedOrganelle(6, r+q, -1*q, (self.organelleRot+300) % 360) - end - - self.hudSystem:updateMutationPoints() -end - --- The first parameter states which sceneNodes to use, starting with "start" and going up 6. -function MicrobeEditor:renderHighlightedOrganelle(start, q, r, rotation) - -- Render the hex under the cursor - local sceneNode = {} - sceneNode[1] = getComponent(self.hudSystem.hoverOrganelle[start], OgreSceneNodeComponent) - for i=2, 8 do - sceneNode[i] = getComponent(self.hudSystem.hoverHex[i-1+(start-1)*7], - OgreSceneNodeComponent) - end - - if self.activeActionName then - local oldData = {["name"]=self.activeActionName, ["q"]=-q, ["r"]=-r, ["rotation"]=(180+rotation) % 360} - local hexes = OrganelleFactory.checkSize(oldData) - local colour = ColourValue(2, 0, 0, 0.4) - local touching = false; - for _, hex in ipairs(hexes) do - if self:surroundsOrganelle(-hex.q + q, -hex.r + r) then - colour = ColourValue(0, 2, 0, 0.4) - end - end - for _, hex in ipairs(hexes) do - local organelle = MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, -hex.q + q, -hex.r + r) - if organelle then - if organelle.name ~= "cytoplasm" then - colour = ColourValue(2, 0, 0, 0.4) - end - end - end - if CEGUIWindow.getWindowUnderMouse():getName() == 'root' then - - local newData = { - ["name"]=self.activeActionName, - ["q"]=-q, - ["r"]=-r, - ["sceneNode"]=sceneNode, - ["rotation"]=(180+rotation) % 360, - ["colour"]=colour - } - - OrganelleFactory.renderOrganelles(newData) - for i=1, 8 do - sceneNode[i].transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) --Vector3(1,1,1) - sceneNode[i].transform:touch() - end - end - end -end - -function MicrobeEditor:takeMutationPoints(amount) - if amount <= self.mutationPoints then - self.mutationPoints = self.mutationPoints - amount - return true - else - return false - end -end - -function MicrobeEditor:performLocationAction() - if (self.activeActionName) then - local func = self.placementFunctions[self.activeActionName] - func(self, self.activeActionName) - end -end - -function MicrobeEditor:setActiveAction(actionName) - self.activeActionName = actionName -end - --- Instead of executing a command, put it in a table with a redo() and undo() function to make it use the Undo-/Redo-Feature. --- Enqueuing it will execute it automatically, so you don't have to write things twice. --- The cost of the action can also be incorporated into this by making it a member of the parameter table. It will be used automatically. -function MicrobeEditor:enqueueAction(action) - if not action.cost or self:takeMutationPoints(action.cost) then - while #self.actionHistory > self.actionIndex do - table.remove(self.actionHistory) - end - self.hudSystem.undoButton:enable() - self.hudSystem.redoButton:disable() - action.redo() - table.insert(self.actionHistory, action) - self.actionIndex = self.actionIndex + 1 - end -end - -function MicrobeEditor:undo() - if self.actionIndex > 0 then - local action = self.actionHistory[self.actionIndex] - action.undo() - if action.cost then - self.mutationPoints = self.mutationPoints + action.cost - end - self.actionIndex = self.actionIndex - 1 - end - -- nothing left to undo? disable undo - if self.actionIndex <= 0 then - self.hudSystem.undoButton:disable() - end - -- upon undoing, redoing is possible - self.hudSystem.redoButton:enable() -end - -function MicrobeEditor:redo() - if self.actionIndex < #self.actionHistory then - self.actionIndex = self.actionIndex + 1 - local action = self.actionHistory[self.actionIndex] - action.redo() - if action.cost then - self.mutationPoints = self.mutationPoints - action.cost - end - end - -- nothing left to redo? disable redo - if self.actionIndex >= #self.actionHistory then - self.hudSystem.redoButton:disable() - end - -- upon redoing, undoing is possible - self.hudSystem.undoButton:enable() -end - -function MicrobeEditor:getMouseHex() - local mousePosition = Engine.mouse:normalizedPosition() - -- Get the position of the cursor in the plane that the microbes is floating in - local rayPoint = getComponent(CAMERA_NAME .. "3", g_luaEngine.currentGameState, - OgreCameraComponent - ):getCameraToViewportRay(mousePosition.x, mousePosition.y):getPoint(0) - - -- Convert to the hex the cursor is currently located over. - local q, r = cartesianToAxial(rayPoint.x, -1*rayPoint.y) -- Negating X to compensate for the fact that we are looking at the opposite side of the normal coordinate system - local qr, rr = cubeToAxial(cubeHexRound(axialToCube(q, r))) -- This requires a conversion to hex cube coordinates and back for proper rounding. - --print(qr, rr) - return qr, rr -end - -function MicrobeEditor:isValidPlacement(organelleType, q, r, rotation) - local data = {["name"]=organelleType, ["q"]=q, ["r"]=r, ["rotation"]=rotation} - local newOrganelle = OrganelleFactory.makeOrganelle(data) - local empty = true - local touching = false; - for s, hex in pairs(OrganelleFactory.checkSize(data)) do - local organelle = MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, hex.q + q, hex.r + r) - if organelle then - if organelle.name ~= "cytoplasm" then - empty = false - end - end - if self:surroundsOrganelle(hex.q + q, hex.r + r) then - touching = true; - end - end - - if empty and touching then - newOrganelle.rotation = data.rotation - return newOrganelle - else - return nil - end -end - -function MicrobeEditor:addOrganelle(organelleType) - local q, r = self:getMouseHex() - - if self.symmetry == 0 then - local organelle = self:isValidPlacement(organelleType, q, r, self.organelleRot) - - if organelle then - if organelleTable[organelle.name].mpCost > self.mutationPoints then return end - self:_addOrganelle(organelle, q, r, self.organelleRot) - end - elseif self.symmetry == 1 then - -- Makes sure that the organelle doesn't overlap on the existing ones. - local organelle = self:isValidPlacement(organelleType, q, r, self.organelleRot) - if (q ~= -1*q or r ~= r+q) then -- If two organelles aren't overlapping - local organelle2 = self:isValidPlacement(organelleType, -1*q, r+q, 360+(-1*self.organelleRot)) - - -- If the organelles were successfully created and have enough MP... - if organelle and organelle2 and organelleTable[organelle.name].mpCost*2 <= self.mutationPoints then - -- Add the organelles to the microbe. - self:_addOrganelle(organelle, q, r, self.organelleRot) - self:_addOrganelle(organelle2, -1*q, r+q, 360+(-1*self.organelleRot)) - end - else - if organelle and organelleTable[organelle.name].mpCost <= self.mutationPoints then - -- Add a organelle to the microbe. - self:_addOrganelle(organelle, q, r, self.organelleRot) - end - end - elseif self.symmetry == 2 then - local organelle = self:isValidPlacement(organelleType, q, r, self.organelleRot) - if q ~= -1*q or r ~= r+q then -- If two organelles aren't overlapping, none are - local organelle2 = self:isValidPlacement(organelleType, -1*q, r+q, 360+(-1*self.organelleRot)) - local organelle3 = self:isValidPlacement(organelleType, -1*q, -1*r, (self.organelleRot+180) % 360) - local organelle4 = self:isValidPlacement(organelleType, q, -1*(r+q), (540+(-1*self.organelleRot)) % 360) - - if organelle and organelle2 and organelle3 and organelle4 and organelleTable[organelle.name].mpCost*4 <= self.mutationPoints then - self:_addOrganelle(organelle, q, r, self.organelleRot) - self:_addOrganelle(organelle2, -1*q, r+q, 360+(-1*self.organelleRot)) - self:_addOrganelle(organelle3, -1*q, -1*r, (self.organelleRot+180) % 360) - self:_addOrganelle(organelle4, q, -1*(r+q), (540+(-1*self.organelleRot)) % 360) - end - else - if organelle and organelleTable[organelle.name].mpCost <= self.mutationPoints then - self:_addOrganelle(organelle, q, r, self.organelleRot) - end - end - elseif self.symmetry == 3 then - local organelle = self:isValidPlacement(organelleType, q, r, self.organelleRot) - if q ~= -1*r or r ~= r+q then -- If two organelles aren't overlapping, none are - local organelle2 = self:isValidPlacement(organelleType, -1*r, r+q, (self.organelleRot+60) % 360) - local organelle3 = self:isValidPlacement(organelleType, -1*(r+q), q, (self.organelleRot+120) % 360) - local organelle4 = self:isValidPlacement(organelleType, -1*q, -1*r, (self.organelleRot+180) % 360) - local organelle5 = self:isValidPlacement(organelleType, r, -1*(r+q), (self.organelleRot+240) % 360) - local organelle6 = self:isValidPlacement(organelleType, r+q, -1*q, (self.organelleRot+300) % 360) - - if organelle and organelle2 and organelle3 and organelle4 and organelle5 and organelle6 - and organelleTable[organelle.name].mpCost*6 <= self.mutationPoints then - self:_addOrganelle(organelle, q, r, self.organelleRot) - self:_addOrganelle(organelle2, -1*r, r+q, (self.organelleRot+60) % 360) - self:_addOrganelle(organelle3, -1*(r+q), q, (self.organelleRot+120) % 360) - self:_addOrganelle(organelle4, -1*q, -1*r, (self.organelleRot+180) % 360) - self:_addOrganelle(organelle5, r, -1*(r+q), (self.organelleRot+240) % 360) - self:_addOrganelle(organelle6, r+q, -1*q, (self.organelleRot+300) % 360) - end - else - if organelle and organelleTable[organelle.name].mpCost <= self.mutationPoints then - self:_addOrganelle(organelle, q, r, self.organelleRot) - end - end - end -end - -function MicrobeEditor:_addOrganelle(organelle, q, r, rotation) - self:enqueueAction({ - cost = organelleTable[organelle.name].mpCost, - redo = function() - local sceneNodeComponent = getComponent(self.currentMicrobeEntity, OgreSceneNodeComponent) - for _, hex in pairs(organelle._hexes) do - -- Check if there is cytoplasm under this organelle. - local cytoplasm = MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, hex.q + q, hex.r + r) - if cytoplasm then - if cytoplasm.name == "cytoplasm" then - MicrobeSystem.removeOrganelle(self.currentMicrobeEntity, hex.q + q, hex.r + r) - sceneNodeComponent.transform:touch() - self.organelleCount = self.organelleCount - 1 - local s = encodeAxial(hex.q + q, hex.r + r) - self.occupiedHexes[s]:destroy() - end - end - self:createHexComponent(hex.q + q, hex.r + r) - end - MicrobeSystem.addOrganelle(self.currentMicrobeEntity, q, r, rotation, organelle) - self.organelleCount = self.organelleCount + 1 - end, - undo = function() - local sceneNodeComponent = getComponent(self.currentMicrobeEntity, OgreSceneNodeComponent) - MicrobeSystem.removeOrganelle(self.currentMicrobeEntity, q, r) - sceneNodeComponent.transform:touch() - self.organelleCount = self.organelleCount - 1 - for _, hex in pairs(organelle._hexes) do - local x, y = axialToCartesian(hex.q + q, hex.r + r) - local s = encodeAxial(hex.q + q, hex.r + r) - self.occupiedHexes[s]:destroy() - end - end - }) -end - -function MicrobeEditor:removeOrganelleAt(q,r) - local organelle = MicrobeSystem.getOrganelleAt(self.currentMicrobeEntity, q, r) - if not (organelle == nil or organelle.name == "nucleus") then -- Don't remove nucleus - if organelle then - for _, hex in pairs(organelle._hexes) do - local s = encodeAxial(hex.q + organelle.position.q, hex.r + organelle.position.r) - self.occupiedHexes[s]:destroy() - end - local storage = organelle:storage() - self:enqueueAction({ - cost = 10, - redo = function() - MicrobeSystem.removeOrganelle(self.currentMicrobeEntity, storage:get("q", 0), storage:get("r", 0)) - local sceneNodeComponent = getComponent(self.currentMicrobeEntity, OgreSceneNodeComponent) - sceneNodeComponent.transform:touch() - self.organelleCount = self.organelleCount - 1 - for _, cytoplasm in pairs(organelle._hexes) do - local s = encodeAxial(cytoplasm.q + storage:get("q", 0), cytoplasm.r + storage:get("r", 0)) - self.occupiedHexes[s]:destroy() - end - end, - undo = function() - local organelle = Organelle.loadOrganelle(storage) - MicrobeSystem.addOrganelle(self.currentMicrobeEntity, storage:get("q", 0), storage:get("r", 0), storage:get("rotation", 0), organelle) - for _, hex in pairs(organelle._hexes) do - self:createHexComponent(hex.q + storage:get("q", 0), hex.r + storage:get("r", 0)) - end - self.organelleCount = self.organelleCount + 1 - end - }) - end - end -end - -function MicrobeEditor:removeOrganelle() - local q, r = self:getMouseHex() - self:removeOrganelleAt(q,r) -end - -function MicrobeEditor:addNucleus() - local nucleusOrganelle = OrganelleFactory.makeOrganelle({["name"]="nucleus", ["q"]=0, ["r"]=0, ["rotation"]=0}) - MicrobeSystem.addOrganelle(self.currentMicrobeEntity, 0, 0, 0, nucleusOrganelle) -end - -function MicrobeEditor:loadMicrobe(entityId) - self.organelleCount = 0 - if self.currentMicrobeEntity ~= nil then - self.currentMicrobeEntity:destroy() - end - self.currentMicrobeEntity = Entity.new(entityId, g_luaEngine.currentGameState.wrapper) - MicrobeSystem.initializeMicrobe(self.currentMicrobeEntity, true) - self.currentMicrobeEntity:stealName("working_microbe") - local sceneNodeComponent = getComponent(self.currentMicrobeEntity, OgreSceneNodeComponent) - sceneNodeComponent.transform.orientation = Quaternion.new(Radian.new(Degree(0)), - Vector3(0, 0, 1))-- Orientation - sceneNodeComponent.transform:touch() - Engine:playerData():setActiveCreature(entityId, GameState.MICROBE_EDITOR) - self.mutationPoints = 0 - -- resetting the action history - it should not become entangled with the local file system - self.actionHistory = {} - self.actionIndex = 0 -end - -function MicrobeEditor:createNewMicrobe() - local action = { - redo = function() - self.organelleCount = 0 - local microbeComponent = getComponent(self.currentMicrobeEntity, MicrobeComponent) - speciesName = microbeComponent.speciesName - if self.currentMicrobeEntity ~= nil then - self.currentMicrobeEntity:destroy() - end - for _, cytoplasm in pairs(self.occupiedHexes) do - cytoplasm:destroy() - end - - self.currentMicrobeEntity = MicrobeSystem.createMicrobeEntity(nil, false, 'Editor_Microbe', true) - microbeComponent = getComponent(self.currentMicrobeEntity, MicrobeComponent) - local sceneNodeComponent = getComponent(self.currentMicrobeEntity, OgreSceneNodeComponent) - self.currentMicrobeEntity:stealName("working_microbe") - sceneNodeComponent.transform:touch() - microbeComponent.speciesName = speciesName - self:addNucleus() - for _, organelle in pairs(microbeComponent.organelles) do - for s, hex in pairs(organelle._hexes) do - self:createHexComponent(hex.q + organelle.position.q, hex.r + organelle.position.r) - end - end - self.mutationPoints = 100 - self.activeActionName = "cytoplasm" - Engine:playerData():setActiveCreature(self.currentMicrobeEntity.id, GameState.MICROBE_EDITOR.wrapper) - end - } - - if self.currentMicrobeEntity ~= nil then - -- that there has already been a microbe in the editor suggests that it was a player action, so it's prepared and filed in for un/redo - local organelleStorage = {} - local previousOrganelleCount = self.organelleCount - local previousMP = self.mutationPoints - local currentMicrobeComponent = getComponent(self.currentMicrobeEntity, MicrobeComponent) - for position,organelle in pairs(currentMicrobeComponent.organelles) do - organelleStorage[position] = organelle:storage() - end - - action.undo = function() - local microbeComponent = getComponent(self.currentMicrobeEntity, MicrobeComponent) - - speciesName = microbeComponent.speciesName - self.currentMicrobeEntity:destroy() -- remove the "new" entity that has replaced the previous one - self.currentMicrobeEntity = MicrobeSystem.createMicrobeEntity(nil, false, 'Editor_Microbe', true) - - microbeComponent = getComponent(self.currentMicrobeEntity, MicrobeComponent) - local sceneNodeComponent = getComponent(self.currentMicrobeEntity, OgreSceneNodeComponent) - - self.currentMicrobeEntity:stealName("working_microbe") - sceneNodeComponent.transform.orientation = Quaternion.new(Radian(0), Vector3(0, 0, 1))-- Orientation - sceneNodeComponent.transform:touch() - microbeComponent.speciesName = speciesName - for position,storage in pairs(organelleStorage) do - local q, r = decodeAxial(position) - MicrobeSystem.addOrganelle(self.currentMicrobeEntity, storage:get("q", 0), storage:get("r", 0), storage:get("rotation", 0), Organelle.loadOrganelle(storage)) - end - for _, cytoplasm in pairs(self.occupiedHexes) do - cytoplasm:destroy() - end - for _, organelle in pairs(microbeComponent.organelles) do - for s, hex in pairs(organelle._hexes) do - self:createHexComponent(hex.q + organelle.position.q, hex.r + organelle.position.r) - end - end - -- no need to add the nucleus manually - it's alreary included in the organelleStorage - self.mutationPoints = previousMP - self.organelleCount = previousOrganelleCount - Engine:playerData():setActiveCreature(self.currentMicrobeEntity.id, GameState.MICROBE_EDITOR.wrapper) - end - self:enqueueAction(action) - else - -- if there's no microbe yet, it can be safely assumed that this is a generated default microbe when opening the editor for the first time, so it's not an action that should be put into the un/redo-feature - action.redo() - end -end diff --git a/scripts/microbe_editor/microbe_editor_hud.as b/scripts/microbe_editor/microbe_editor_hud.as new file mode 100644 index 00000000000..b8b4b7c8ce2 --- /dev/null +++ b/scripts/microbe_editor/microbe_editor_hud.as @@ -0,0 +1,530 @@ +#include "microbe_editor.as" + +class MicrobeEditorHudSystem : ScriptSystem{ + + void Init(GameWorld@ w){ + + @this.world = cast(w); + + assert(this.world !is null, "MicrobeEditorHudSystem didn't get proper world"); + + @editor = MicrobeEditor(this); + editor.init(); + + // // This seems really cluttered, there must be a better way. + // for(i=1, 42){ + // this.hoverHex[i] = Entity("hover-hex" .. i, gameState.wrapper); + // auto sceneNode = OgreSceneNodeComponent(); + // sceneNode.transform.position = Vector3(0,0,0); + // sceneNode.transform.touch(); + // sceneNode.meshName = "hex.mesh"; + // sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE); + // this.hoverHex[i]:addComponent(sceneNode); + // } + // for(i=1, 6){ + // this.hoverOrganelle[i] = Entity("hover-organelle" .. i, gameState.wrapper); + // auto sceneNode = OgreSceneNodeComponent(); + // sceneNode.transform.position = Vector3(0,0,0); + // sceneNode.transform.touch(); + // sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE); + // this.hoverOrganelle[i]:addComponent(sceneNode); + // } + + + // auto root = this.gameState.guiWindow; + // this.mpLabel = root.getChild("MpPanel"):getChild("MpBar"):getChild("NumberLabel"); + // this.mpProgressBar = root.getChild("MpPanel"):getChild("MpBar"); + // this.mpProgressBar.setProperty("ThriveGeneric/MpBar", "FillImage"); + + // auto nucleusButton = root.getChild("NewButton"); + // auto flagellumButton = root.getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddFlagellum"); + // auto cytoplasmButton = root.getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddCytoplasm"); + // auto mitochondriaButton = root.getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddMitochondrion"); + // auto vacuoleButton = root.getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddVacuole"); + // auto toxinButton = root.getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddToxinVacuole"); + // auto chloroplastButton = root.getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddChloroplast"); + + // this.organelleButtons["nucleus"] = nucleusButton; + // this.organelleButtons["flagellum"] = flagellumButton; + // this.organelleButtons["cytoplasm"] = cytoplasmButton; + // this.organelleButtons["mitochondrion"] = mitochondriaButton; + // this.organelleButtons["chloroplast"] = chloroplastButton; + // this.organelleButtons["vacuole"] = vacuoleButton; + // this.organelleButtons["Toxin"] = toxinButton; + // this.activeButton = null; + + // // nucleusButton.registerEventHandler("Clicked", function() this.nucleusClicked() }); + // // flagellumButton.registerEventHandler("Clicked", function() this.flagellumClicked() }); + // // cytoplasmButton.registerEventHandler("Clicked", function() this.cytoplasmClicked() }); + // // mitochondriaButton.registerEventHandler("Clicked", function() this.mitochondriaClicked() }); + // // chloroplastButton.registerEventHandler("Clicked", function() this.chloroplastClicked() }); + // // vacuoleButton.registerEventHandler("Clicked", function() this.vacuoleClicked() }); + // // toxinButton.registerEventHandler("Clicked", function() this.toxinClicked() }); + + // // this.saveLoadPanel = root.getChild("SaveLoadPanel") + // // this.creationsListbox = this.saveLoadPanel.getChild("SavedCreations") + // this.undoButton = root.getChild("UndoButton"); + // // this.undoButton.registerEventHandler("Clicked", function() this.editor.undo() }); + // this.redoButton = root.getChild("RedoButton"); + // // this.redoButton.registerEventHandler("Clicked", function() this.editor.redo() }); + // this.symmetryButton = root.getChild("SymmetryButton"); + // // this.symmetryButton.registerEventHandler("Clicked", function() this.changeSymmetry() }); + + // root.getChild("FinishButton"):registerEventHandler("Clicked", playClicked); + // //root.getChild("BottomSection"):getChild("MenuButton"):registerEventHandler("Clicked", this.menuButtonClicked) + // // root.getChild("MenuButton"):registerEventHandler("Clicked", function() this.menuButtonClicked() }); + // // root.getChild("PauseMenu"):getChild("MainMenuButton"):registerEventHandler("Clicked", function() this.menuMainMenuClicked() }); + // // root.getChild("PauseMenu"):getChild("ResumeButton"):registerEventHandler("Clicked", function() this.resumeButtonClicked() }); + // // root.getChild("PauseMenu"):getChild("CloseHelpButton"):registerEventHandler("Clicked", function() this.closeHelpButtonClicked() }); + // // root.getChild("PauseMenu"):getChild("QuitButton"):registerEventHandler("Clicked", function() this.quitButtonClicked() }); + // //root.getChild("SaveMicrobeButton"):registerEventHandler("Clicked", function() this.saveCreationClicked() }) + // //root.getChild("LoadMicrobeButton"):registerEventHandler("Clicked", function() this.loadCreationClicked() }) + + // this.helpPanel = root.getChild("PauseMenu"):getChild("HelpPanel"); + // root.getChild("PauseMenu"):getChild("HelpButton"):registerEventHandler("Clicked", function() this.helpButtonClicked() }); + + // // This was commented out in the Lua code + // // // Set species name and cut it off if it is too long. + // // //[[ auto name = this.nameLabel.getText() + // // if(string.len(name) > 18){ + // // name = string.sub(name, 1, 15); + // // name = name .. "..."; + // // } + // // this.nameLabel.setText(name); //]] + + // for(typeName,button in pairs(global_activeMicrobeEditorHudSystem.organelleButtons)){ + // print(typeName); + // if(Engine.playerData():lockedMap():isLocked(typeName)){ + // button.disable(); + // } else { + // button.enable(); + // } + // } + } + + void Release(){ + + } + + void Run(){ + + int logicTime = TICKSPEED; + this.editor.update(logicTime); + + // for(i=1, 42){ + // auto sceneNode = getComponent(this.hoverHex[i], OgreSceneNodeComponent); + // sceneNode.transform.position = Vector3(0,0,0); + // sceneNode.transform.scale = Vector3(0,0,0); + // sceneNode.transform.touch(); + // } + // for(i=1, 6){ + // auto sceneNode = getComponent(this.hoverOrganelle[i], OgreSceneNodeComponent); + // sceneNode.transform.position = Vector3(0,0,0); + // sceneNode.transform.scale = Vector3(0,0,0); + // sceneNode.transform.touch(); + // } + + // // This is totally the wrong place to have this + // // Handle input + // if(Engine.mouse.wasButtonPressed(Mouse.MB_Left)){ + // this.editor.performLocationAction(); + // } + // if(Engine.mouse.wasButtonPressed(Mouse.MB_Right)){ + // this.removeClicked(); + // this.editor.performLocationAction(); + // } + // if(keyCombo(kmp.togglemenu)){ + // this.menuButtonClicked(); + // } else if(keyCombo(kmp.newmicrobe)){ + // // These global event handlers are defined in microbe_editor_hud.lua + // this.nucleusClicked(); + // } else if(keyCombo(kmp.redo)){ + // this.editor.redo(); + // } else if(keyCombo(kmp.remove)){ + // this.removeClicked(); + // this.editor.performLocationAction(); + // } else if(keyCombo(kmp.undo)){ + // this.editor.undo(); + // } else if(keyCombo(kmp.vacuole)){ + // this.vacuoleClicked(); + // this.editor.performLocationAction(); + // } else if(keyCombo(kmp.oxytoxyvacuole)){ + // if(not Engine.playerData():lockedMap():isLocked("Toxin")){ + // this.toxinClicked(); + // this.editor.performLocationAction(); + // } + // } else if(keyCombo(kmp.flagellum)){ + // this.flagellumClicked(); + // this.editor.performLocationAction(); + // } else if(keyCombo(kmp.mitochondrion)){ + // this.mitochondriaClicked(); + // this.editor.performLocationAction(); + // //} else if(Engine.keyboard.wasKeyPressed(Keyboard.KC_A) and this.editor.currentMicrobe !is null){ + // // this.aminoSynthesizerClicked() + // // this.editor.performLocationAction() + // } else if(keyCombo(kmp.chloroplast)){ + // if(not Engine.playerData():lockedMap():isLocked("Chloroplast")){ + // this.chloroplastClicked(); + // this.editor.performLocationAction(); + // } + // } else if(keyCombo(kmp.togglegrid)){ + // if(this.editor.gridVisible){ + // this.editor.gridSceneNode.visible = false; + // this.editor.gridVisible = false; + // } else { + // this.editor.gridSceneNode.visible = true; + // this.editor.gridVisible = true; + // } + // } else if(keyCombo(kmp.gotostage)){ + // playClicked(); + // } else if(keyCombo(kmp.rename)){ + // this.updateMicrobeName(); + // } + + // if(Engine.keyboard.wasKeyPressed(KEYCODE.KC_LEFT) or + // Engine.keyboard.wasKeyPressed(KEYCODE.KC_A)){ + + // this.editor.organelleRot = (this.editor.organelleRot + 60)%360; + // } + // if(Engine.keyboard.wasKeyPressed(KEYCODE.KC_RIGHT) or + // Engine.keyboard.wasKeyPressed(KEYCODE.KC_D)){ + + // this.editor.organelleRot = (this.editor.organelleRot - 60)%360; + // } + + // if(Engine.keyboard.isKeyDown(KEYCODE.KC_LSHIFT)){ + // properties = getComponent(CAMERA_NAME .. 3, this.gameState, OgreCameraComponent).properties; + // newFovY = properties.fovY + Degree(Engine.mouse.scrollChange()/10); + // if(newFovY < Degree(10)){ + // newFovY = Degree(10); + // } else if(newFovY > Degree(120)){ + // newFovY = Degree(120); + // } + // properties.fovY = newFovY; + // properties.touch(); + // } else { + + // } + } + + // Nodes not used + void Clear(){ + } + + void CreateAndDestroyNodes(){ + } + + private MicrobeEditor@ editor = null; + private MicrobeEditorWorld@ world; + + // // Scene nodes for the organelle cursors for symmetry. + // this.hoverHex = {}; + // this.hoverOrganelle = {}; + + // this.saveLoadPanel = null; + // this.creationsListbox = null; + // this.creationFileMap = {} // Map from player creation name to filepath + // this.activeButton = null; // stores button, not name + // this.helpPanelOpen = false; + // this.menuOpen = false; +} + +// void MicrobeEditorHudSystem.loadmicrobeSelectionChanged(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// } + +// void MicrobeEditorHudSystem.setActiveAction(actionName){ +// this.editor.setActiveAction(actionName) +// if(actionName == "nucleus"){ +// // For now we simply create a new microbe with the nucleus button +// this.editor.performLocationAction() +// } +// end + + +// void MicrobeEditorHudSystem.update(renderTime, logicTime){ + +// void MicrobeEditorHudSystem.updateMutationPoints() { +// this.mpProgressBar.progressbarSetProgress(this.editor.mutationPoints/50) +// this.mpLabel.setText("" .. this.editor.mutationPoints) +// } + +// ////////////////////////////////////////////////////////////////- +// // Event handlers //////////////////////////////////////////////- + + +// void playClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// g_luaEngine.setCurrentGameState(GameState.MICROBE) +// } + +// void menuPlayClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// g_luaEngine.currentGameState.guiWindow.getChild("MenuPanel"):hide() +// playClicked() +// } + +// void MicrobeEditorHudSystem.menuMainMenuClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// g_luaEngine.setCurrentGameState(GameState.MAIN_MENU) +// } + +// void MicrobeEditorHudSystem.quitButtonClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// Engine.quit() +// } + +// // the rest of the event handlers are MicrobeEditorHudSystem methods + +// void MicrobeEditorHudSystem.helpButtonClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("HelpPanel"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("CloseHelpButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("ResumeButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("QuicksaveButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("SaveGameButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("LoadGameButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("StatsButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("HelpButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("OptionsButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("MainMenuButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("QuitButton"):hide() +// this.helpOpen = not this.helpOpen +// } + +// void MicrobeEditorHudSystem.closeHelpButtonClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("HelpPanel"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("CloseHelpButton"):hide() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("ResumeButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("QuicksaveButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("SaveGameButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("LoadGameButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("StatsButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("HelpButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("OptionsButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("MainMenuButton"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):getChild("QuitButton"):show() +// this.helpOpen = not this.helpOpen +// } + +// void MicrobeEditorHudSystem.nucleusClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.setActiveAction("nucleus") +// } + +// void MicrobeEditorHudSystem.flagellumClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = this.organelleButtons["flagellum"] +// this.activeButton.disable() +// this.setActiveAction("flagellum") +// } + +// void MicrobeEditorHudSystem.cytoplasmClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = this.organelleButtons["cytoplasm"] +// this.activeButton.disable() +// this.setActiveAction("cytoplasm") +// } + +// void MicrobeEditorHudSystem.mitochondriaClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = this.organelleButtons["mitochondrion"] +// this.activeButton.disable() +// this.setActiveAction("mitochondrion") +// } + +// void MicrobeEditorHudSystem.chloroplastClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = this.organelleButtons["chloroplast"] +// this.activeButton.disable() +// this.setActiveAction("chloroplast") +// } + +// void MicrobeEditorHudSystem.aminoSynthesizerClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = this.organelleButtons["aminosynthesizer"] +// this.activeButton.disable() +// this.setActiveAction("aminosynthesizer") +// } + +// void MicrobeEditorHudSystem.vacuoleClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = this.organelleButtons["vacuole"] +// this.activeButton.disable() +// this.setActiveAction("vacuole") +// } + +// void MicrobeEditorHudSystem.toxinClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = this.organelleButtons["Toxin"] +// this.activeButton.disable() +// this.setActiveAction("oxytoxy") +// } + + +// void MicrobeEditorHudSystem.removeClicked(){ +// if(this.activeButton !is null){ +// this.activeButton.enable() +// } +// this.activeButton = null +// this.setActiveAction("remove") +// } + +// void MicrobeEditorHudSystem.rootSaveCreationClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// print ("Save button clicked") +// //[[ +// panel = this.saveLoadPanel +// panel.getChild("SaveButton"):show() +// panel.getChild("NameTextbox"):show() +// panel.getChild("CreationNameDialogLabel"):show() +// panel.getChild("LoadButton"):hide() +// panel.getChild("SavedCreations"):hide() +// panel.show()//]] +// } +// //[[ +// void MicrobeEditorHudSystem.rootLoadCreationClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// panel = this.saveLoadPanel +// // panel.getChild("SaveButton"):hide() +// // root.getChild("CreationNameDialogLabel"):hide() +// panel.getChild("LoadButton"):show() +// panel.getChild("SavedCreations"):show() +// panel.show() +// this.creationsListbox.listWidgetResetList() +// this.creationFileMap = {} +// i = 0 +// pathsString = Engine.getCreationFileList("microbe") +// // using pattern matching for splitting on spaces +// for(path in string.gmatch(pathsString, "%S+") ){ +// // this is unsafe when one of the paths is, for example, C:\\Application Data\Thrive\saves +// pathSep = package.config.sub(1,1) // / for unix, \ for windows +// text = string.sub(path, string.len(path) - string.find(path.reverse(), pathSep) + 2) +// this.creationsListbox.listWidgetAddItem(text) +// this.creationFileMap[text] = path +// i = i + 1 +// } +// // this.creationsListbox.itemListboxHandleUpdatedItemData() +// } + +// void MicrobeEditorHudSystem.saveCreationClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// name = this.editor.currentMicrobe.microbe.speciesName +// print("saving "..name) +// // Todo: Additional input sanitation +// name, _ = string.gsub(name, "%s+", "_") // replace whitespace with underscore +// if(string.match(name, "^[%w_]+$") == null){ +// print("unsanitary name: "..name) // should we do the test before whitespace sanitization? +// } else if(string.len(name) > 0){ +// Engine.saveCreation(this.editor.currentMicrobe.entity.id, name, "microbe") +// } +// end + +// void MicrobeEditorHudSystem.loadCreationClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// item = this.creationsListbox.listWidgetGetFirstSelectedItemText() +// if(this.creationFileMap[item] !is null){ +// entity = Engine.loadCreation(this.creationFileMap[item]) +// this.updateMicrobeName(Microbe(Entity(entity), true).microbe.speciesName) +// this.editor.loadMicrobe(entity) +// panel.hide() +// } +// end +// //]] + +// // useful debug functions + +// void MicrobeEditorHudSystem.loadByName(name){ +// if(string.find(name, ".microbe")){ +// print("note, you don't need to add the .microbe extension") +// } else +// name = name..".microbe" +// } +// name, _ = string.gsub(name, "%s+", "_") +// creationFileMap = {} +// i = 0 +// pathsString = Engine.getCreationFileList("microbe") +// // using pattern matching for splitting on spaces +// for(path in string.gmatch(pathsString, "%S+") ){ +// // this is unsafe when one of the paths is, for example, C:\\Application Data\Thrive\saves +// pathSep = package.config.sub(1,1) // / for unix, \ for windows +// text = string.sub(path, string.len(path) - string.find(path.reverse(), pathSep) + 2) +// creationFileMap[text] = path +// i = i + 1 +// } +// entity = Engine.loadCreation(creationFileMap[name]) +// this.editor.loadMicrobe(entity) +// //this.nameLabel.setText(this.editor.currentMicrobe.microbe.speciesName) +// } + +// void MicrobeEditorHudSystem.changeSymmetry(){ +// this.editor.symmetry = (this.editor.symmetry+1)%4 + +// if(this.editor.symmetry == 0){ +// this.symmetryButton.getChild("2xSymmetry"):hide() +// this.symmetryButton.getChild("4xSymmetry"):hide() +// this.symmetryButton.getChild("6xSymmetry"):hide() +// } else if(this.editor.symmetry == 1){ +// this.symmetryButton.getChild("2xSymmetry"):show() +// this.symmetryButton.getChild("4xSymmetry"):hide() +// this.symmetryButton.getChild("6xSymmetry"):hide() +// } else if(this.editor.symmetry == 2){ +// this.symmetryButton.getChild("2xSymmetry"):hide() +// this.symmetryButton.getChild("4xSymmetry"):show() +// this.symmetryButton.getChild("6xSymmetry"):hide() +// } else if(this.editor.symmetry == 3){ +// this.symmetryButton.getChild("2xSymmetry"):hide() +// this.symmetryButton.getChild("4xSymmetry"):hide() +// this.symmetryButton.getChild("6xSymmetry"):show() +// } +// end + +// void saveMicrobe() global_activeMicrobeEditorHudSystem.saveCreationClicked() }{ +// void loadMicrobe(name) global_activeMicrobeEditorHudSystem.loadByName(name) }{ + +// void MicrobeEditorHudSystem.menuButtonClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// print("played sound") +// this.gameState.guiWindow.getChild("PauseMenu"):show() +// this.gameState.guiWindow.getChild("PauseMenu"):moveToFront() +// Engine.pauseGame() +// this.menuOpen = true +// } + +// void MicrobeEditorHudSystem.resumeButtonClicked(){ +// getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent +// ):playSound("button-hover-click") +// print("played sound") +// this.gameState.guiWindow.getChild("PauseMenu"):hide() +// Engine.resumeGame() +// this.menuOpen = false +// } diff --git a/scripts/microbe_editor/microbe_editor_hud.lua b/scripts/microbe_editor/microbe_editor_hud.lua deleted file mode 100644 index 62b61d7a9c9..00000000000 --- a/scripts/microbe_editor/microbe_editor_hud.lua +++ /dev/null @@ -1,520 +0,0 @@ --- Updates the hud with relevant information -MicrobeEditorHudSystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - self.organelleButtons = {} - self.initialized = false - self.editor = MicrobeEditor.new(self) - - -- Scene nodes for the organelle cursors for symmetry. - self.hoverHex = {} - self.hoverOrganelle = {} - - self.saveLoadPanel = nil - self.creationsListbox = nil - self.creationFileMap = {} -- Map from player creation name to filepath - self.activeButton = nil -- stores button, not name - self.helpPanelOpen = false - self.menuOpen = false - - end -) - -function MicrobeEditorHudSystem:init(gameState) - LuaSystem.init(self, "MicrobeEditorHudSystem", gameState) - self.editor:init(gameState) - - -- This seems really cluttered, there must be a better way. - for i=1, 42 do - self.hoverHex[i] = Entity.new("hover-hex" .. i, gameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.transform.position = Vector3(0,0,0) - sceneNode.transform:touch() - sceneNode.meshName = "hex.mesh" - sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) - self.hoverHex[i]:addComponent(sceneNode) - end - for i=1, 6 do - self.hoverOrganelle[i] = Entity.new("hover-organelle" .. i, gameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.transform.position = Vector3(0,0,0) - sceneNode.transform:touch() - sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) - self.hoverOrganelle[i]:addComponent(sceneNode) - end - - - local root = self.gameState.guiWindow - self.mpLabel = root:getChild("MpPanel"):getChild("MpBar"):getChild("NumberLabel") - self.mpProgressBar = root:getChild("MpPanel"):getChild("MpBar") - self.mpProgressBar:setProperty("ThriveGeneric/MpBar", "FillImage") - - local nucleusButton = root:getChild("NewButton") - local flagellumButton = root:getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddFlagellum") - local cytoplasmButton = root:getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddCytoplasm") - local mitochondriaButton = root:getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddMitochondrion") - local vacuoleButton = root:getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddVacuole") - local toxinButton = root:getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddToxinVacuole") - local chloroplastButton = root:getChild("EditPanel"):getChild("StructurePanel"):getChild("StructureScroll"):getChild("AddChloroplast") - - self.organelleButtons["nucleus"] = nucleusButton - self.organelleButtons["flagellum"] = flagellumButton - self.organelleButtons["cytoplasm"] = cytoplasmButton - self.organelleButtons["mitochondrion"] = mitochondriaButton - self.organelleButtons["chloroplast"] = chloroplastButton - self.organelleButtons["vacuole"] = vacuoleButton - self.organelleButtons["Toxin"] = toxinButton - self.activeButton = nil - - nucleusButton:registerEventHandler("Clicked", function() self:nucleusClicked() end) - flagellumButton:registerEventHandler("Clicked", function() self:flagellumClicked() end) - cytoplasmButton:registerEventHandler("Clicked", function() self:cytoplasmClicked() end) - mitochondriaButton:registerEventHandler("Clicked", function() self:mitochondriaClicked() end) - chloroplastButton:registerEventHandler("Clicked", function() self:chloroplastClicked() end) - vacuoleButton:registerEventHandler("Clicked", function() self:vacuoleClicked() end) - toxinButton:registerEventHandler("Clicked", function() self:toxinClicked() end) - - -- self.saveLoadPanel = root:getChild("SaveLoadPanel") - -- self.creationsListbox = self.saveLoadPanel:getChild("SavedCreations") - self.undoButton = root:getChild("UndoButton") - self.undoButton:registerEventHandler("Clicked", function() self.editor:undo() end) - self.redoButton = root:getChild("RedoButton") - self.redoButton:registerEventHandler("Clicked", function() self.editor:redo() end) - self.symmetryButton = root:getChild("SymmetryButton") - self.symmetryButton:registerEventHandler("Clicked", function() self:changeSymmetry() end) - - root:getChild("FinishButton"):registerEventHandler("Clicked", playClicked) - --root:getChild("BottomSection"):getChild("MenuButton"):registerEventHandler("Clicked", self:menuButtonClicked) - root:getChild("MenuButton"):registerEventHandler("Clicked", function() self:menuButtonClicked() end) - root:getChild("PauseMenu"):getChild("MainMenuButton"):registerEventHandler("Clicked", function() self:menuMainMenuClicked() end) - root:getChild("PauseMenu"):getChild("ResumeButton"):registerEventHandler("Clicked", function() self:resumeButtonClicked() end) - root:getChild("PauseMenu"):getChild("CloseHelpButton"):registerEventHandler("Clicked", function() self:closeHelpButtonClicked() end) - root:getChild("PauseMenu"):getChild("QuitButton"):registerEventHandler("Clicked", function() self:quitButtonClicked() end) - --root:getChild("SaveMicrobeButton"):registerEventHandler("Clicked", function() self:saveCreationClicked() end) - --root:getChild("LoadMicrobeButton"):registerEventHandler("Clicked", function() self:loadCreationClicked() end) - - self.helpPanel = root:getChild("PauseMenu"):getChild("HelpPanel") - root:getChild("PauseMenu"):getChild("HelpButton"):registerEventHandler("Clicked", function() self:helpButtonClicked() end) - - -- Set species name and cut it off if it is too long. - --[[ local name = self.nameLabel:getText() - if string.len(name) > 18 then - name = string.sub(name, 1, 15) - name = name .. "..." - end - self.nameLabel:setText(name) --]] -end - -function MicrobeEditorHudSystem:loadmicrobeSelectionChanged() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") -end - -function MicrobeEditorHudSystem:activate() - global_activeMicrobeEditorHudSystem = self -- Global reference for event handlers - self.editor:activate() - for typeName,button in pairs(global_activeMicrobeEditorHudSystem.organelleButtons) do - print(typeName) - if Engine:playerData():lockedMap():isLocked(typeName) then - button:disable() - else - button:enable() - end - end -end - -function MicrobeEditorHudSystem:setActiveAction(actionName) - self.editor:setActiveAction(actionName) - if actionName == "nucleus" then - -- For now we simply create a new microbe with the nucleus button - self.editor:performLocationAction() - end -end - - -function MicrobeEditorHudSystem:update(renderTime, logicTime) - for i=1, 42 do - local sceneNode = getComponent(self.hoverHex[i], OgreSceneNodeComponent) - sceneNode.transform.position = Vector3(0,0,0) - sceneNode.transform.scale = Vector3(0,0,0) - sceneNode.transform:touch() - end - for i=1, 6 do - local sceneNode = getComponent(self.hoverOrganelle[i], OgreSceneNodeComponent) - sceneNode.transform.position = Vector3(0,0,0) - sceneNode.transform.scale = Vector3(0,0,0) - sceneNode.transform:touch() - end - self.editor:update(renderTime, logicTime) - - -- Handle input - if Engine.mouse:wasButtonPressed(Mouse.MB_Left) then - self.editor:performLocationAction() - end - if Engine.mouse:wasButtonPressed(Mouse.MB_Right) then - self:removeClicked() - self.editor:performLocationAction() - end - if keyCombo(kmp.togglemenu) then - self:menuButtonClicked() - elseif keyCombo(kmp.newmicrobe) then - -- These global event handlers are defined in microbe_editor_hud.lua - self:nucleusClicked() - elseif keyCombo(kmp.redo) then - self.editor:redo() - elseif keyCombo(kmp.remove) then - self:removeClicked() - self.editor:performLocationAction() - elseif keyCombo(kmp.undo) then - self.editor:undo() - elseif keyCombo(kmp.vacuole) then - self:vacuoleClicked() - self.editor:performLocationAction() - elseif keyCombo(kmp.oxytoxyvacuole) then - if not Engine:playerData():lockedMap():isLocked("Toxin") then - self:toxinClicked() - self.editor:performLocationAction() - end - elseif keyCombo(kmp.flagellum) then - self:flagellumClicked() - self.editor:performLocationAction() - elseif keyCombo(kmp.mitochondrion) then - self:mitochondriaClicked() - self.editor:performLocationAction() - --elseif Engine.keyboard:wasKeyPressed(Keyboard.KC_A) and self.editor.currentMicrobe ~= nil then - -- self:aminoSynthesizerClicked() - -- self.editor:performLocationAction() - elseif keyCombo(kmp.chloroplast) then - if not Engine:playerData():lockedMap():isLocked("Chloroplast") then - self:chloroplastClicked() - self.editor:performLocationAction() - end - elseif keyCombo(kmp.togglegrid) then - if self.editor.gridVisible then - self.editor.gridSceneNode.visible = false; - self.editor.gridVisible = false - else - self.editor.gridSceneNode.visible = true; - self.editor.gridVisible = true - end - elseif keyCombo(kmp.gotostage) then - playClicked() - elseif keyCombo(kmp.rename) then - self:updateMicrobeName() - end - - if Engine.keyboard:wasKeyPressed(KEYCODE.KC_LEFT) or - Engine.keyboard:wasKeyPressed(KEYCODE.KC_A) then - - self.editor.organelleRot = (self.editor.organelleRot + 60)%360 - end - if Engine.keyboard:wasKeyPressed(KEYCODE.KC_RIGHT) or - Engine.keyboard:wasKeyPressed(KEYCODE.KC_D) then - - self.editor.organelleRot = (self.editor.organelleRot - 60)%360 - end - - if keyCombo(kmp.screenshot) then - Engine:screenShot("screenshot.png") - end - - if Engine.keyboard:isKeyDown(KEYCODE.KC_LSHIFT) then - properties = getComponent(CAMERA_NAME .. 3, self.gameState, OgreCameraComponent).properties - newFovY = properties.fovY + Degree(Engine.mouse:scrollChange()/10) - if newFovY < Degree(10) then - newFovY = Degree(10) - elseif newFovY > Degree(120) then - newFovY = Degree(120) - end - properties.fovY = newFovY - properties:touch() - else - - end -end - -function MicrobeEditorHudSystem:updateMutationPoints() - self.mpProgressBar:progressbarSetProgress(self.editor.mutationPoints/50) - self.mpLabel:setText("" .. self.editor.mutationPoints) -end - ------------------------------------------------------------------ --- Event handlers ----------------------------------------------- - - -function playClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - g_luaEngine:setCurrentGameState(GameState.MICROBE) -end - -function menuPlayClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - g_luaEngine.currentGameState.guiWindow:getChild("MenuPanel"):hide() - playClicked() -end - -function MicrobeEditorHudSystem:menuMainMenuClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - g_luaEngine:setCurrentGameState(GameState.MAIN_MENU) -end - -function MicrobeEditorHudSystem:quitButtonClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - Engine:quit() -end - --- the rest of the event handlers are MicrobeEditorHudSystem methods - -function MicrobeEditorHudSystem:helpButtonClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - self.gameState.guiWindow:getChild("PauseMenu"):getChild("HelpPanel"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("CloseHelpButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("ResumeButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("QuicksaveButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("SaveGameButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("LoadGameButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("StatsButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("HelpButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("OptionsButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("MainMenuButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("QuitButton"):hide() - self.helpOpen = not self.helpOpen -end - -function MicrobeEditorHudSystem:closeHelpButtonClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - self.gameState.guiWindow:getChild("PauseMenu"):getChild("HelpPanel"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("CloseHelpButton"):hide() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("ResumeButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("QuicksaveButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("SaveGameButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("LoadGameButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("StatsButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("HelpButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("OptionsButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("MainMenuButton"):show() - self.gameState.guiWindow:getChild("PauseMenu"):getChild("QuitButton"):show() - self.helpOpen = not self.helpOpen -end - -function MicrobeEditorHudSystem:nucleusClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self:setActiveAction("nucleus") -end - -function MicrobeEditorHudSystem:flagellumClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = self.organelleButtons["flagellum"] - self.activeButton:disable() - self:setActiveAction("flagellum") -end - -function MicrobeEditorHudSystem:cytoplasmClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = self.organelleButtons["cytoplasm"] - self.activeButton:disable() - self:setActiveAction("cytoplasm") -end - -function MicrobeEditorHudSystem:mitochondriaClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = self.organelleButtons["mitochondrion"] - self.activeButton:disable() - self:setActiveAction("mitochondrion") -end - -function MicrobeEditorHudSystem:chloroplastClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = self.organelleButtons["chloroplast"] - self.activeButton:disable() - self:setActiveAction("chloroplast") -end - -function MicrobeEditorHudSystem:aminoSynthesizerClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = self.organelleButtons["aminosynthesizer"] - self.activeButton:disable() - self:setActiveAction("aminosynthesizer") -end - -function MicrobeEditorHudSystem:vacuoleClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = self.organelleButtons["vacuole"] - self.activeButton:disable() - self:setActiveAction("vacuole") -end - -function MicrobeEditorHudSystem:toxinClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = self.organelleButtons["Toxin"] - self.activeButton:disable() - self:setActiveAction("oxytoxy") -end - - -function MicrobeEditorHudSystem:removeClicked() - if self.activeButton ~= nil then - self.activeButton:enable() - end - self.activeButton = nil - self:setActiveAction("remove") -end - -function MicrobeEditorHudSystem:rootSaveCreationClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - print ("Save button clicked") - --[[ - panel = self.saveLoadPanel - panel:getChild("SaveButton"):show() - panel:getChild("NameTextbox"):show() - panel:getChild("CreationNameDialogLabel"):show() - panel:getChild("LoadButton"):hide() - panel:getChild("SavedCreations"):hide() - panel:show()--]] -end ---[[ -function MicrobeEditorHudSystem:rootLoadCreationClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - panel = self.saveLoadPanel - -- panel:getChild("SaveButton"):hide() - -- root:getChild("CreationNameDialogLabel"):hide() - panel:getChild("LoadButton"):show() - panel:getChild("SavedCreations"):show() - panel:show() - self.creationsListbox:listWidgetResetList() - self.creationFileMap = {} - i = 0 - pathsString = Engine:getCreationFileList("microbe") - -- using pattern matching for splitting on spaces - for path in string.gmatch(pathsString, "%S+") do - -- this is unsafe when one of the paths is, for example, C:\\Application Data\Thrive\saves - pathSep = package.config:sub(1,1) -- / for unix, \ for windows - text = string.sub(path, string.len(path) - string.find(path:reverse(), pathSep) + 2) - self.creationsListbox:listWidgetAddItem(text) - self.creationFileMap[text] = path - i = i + 1 - end - -- self.creationsListbox:itemListboxHandleUpdatedItemData() -end - -function MicrobeEditorHudSystem:saveCreationClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - name = self.editor.currentMicrobe.microbe.speciesName - print("saving "..name) - -- Todo: Additional input sanitation - name, _ = string.gsub(name, "%s+", "_") -- replace whitespace with underscore - if string.match(name, "^[%w_]+$") == nil then - print("unsanitary name: "..name) -- should we do the test before whitespace sanitization? - elseif string.len(name) > 0 then - Engine:saveCreation(self.editor.currentMicrobe.entity.id, name, "microbe") - end -end - -function MicrobeEditorHudSystem:loadCreationClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - item = self.creationsListbox:listWidgetGetFirstSelectedItemText() - if self.creationFileMap[item] ~= nil then - entity = Engine:loadCreation(self.creationFileMap[item]) - self:updateMicrobeName(Microbe(Entity(entity), true).microbe.speciesName) - self.editor:loadMicrobe(entity) - panel:hide() - end -end ---]] - --- useful debug functions - -function MicrobeEditorHudSystem:loadByName(name) - if string.find(name, ".microbe") then - print("note, you don't need to add the .microbe extension") - else - name = name..".microbe" - end - name, _ = string.gsub(name, "%s+", "_") - creationFileMap = {} - i = 0 - pathsString = Engine:getCreationFileList("microbe") - -- using pattern matching for splitting on spaces - for path in string.gmatch(pathsString, "%S+") do - -- this is unsafe when one of the paths is, for example, C:\\Application Data\Thrive\saves - pathSep = package.config:sub(1,1) -- / for unix, \ for windows - text = string.sub(path, string.len(path) - string.find(path:reverse(), pathSep) + 2) - creationFileMap[text] = path - i = i + 1 - end - entity = Engine:loadCreation(creationFileMap[name]) - self.editor:loadMicrobe(entity) - --self.nameLabel:setText(self.editor.currentMicrobe.microbe.speciesName) -end - -function MicrobeEditorHudSystem:changeSymmetry() - self.editor.symmetry = (self.editor.symmetry+1)%4 - - if self.editor.symmetry == 0 then - self.symmetryButton:getChild("2xSymmetry"):hide() - self.symmetryButton:getChild("4xSymmetry"):hide() - self.symmetryButton:getChild("6xSymmetry"):hide() - elseif self.editor.symmetry == 1 then - self.symmetryButton:getChild("2xSymmetry"):show() - self.symmetryButton:getChild("4xSymmetry"):hide() - self.symmetryButton:getChild("6xSymmetry"):hide() - elseif self.editor.symmetry == 2 then - self.symmetryButton:getChild("2xSymmetry"):hide() - self.symmetryButton:getChild("4xSymmetry"):show() - self.symmetryButton:getChild("6xSymmetry"):hide() - elseif self.editor.symmetry == 3 then - self.symmetryButton:getChild("2xSymmetry"):hide() - self.symmetryButton:getChild("4xSymmetry"):hide() - self.symmetryButton:getChild("6xSymmetry"):show() - end -end - -function saveMicrobe() global_activeMicrobeEditorHudSystem:saveCreationClicked() end -function loadMicrobe(name) global_activeMicrobeEditorHudSystem:loadByName(name) end - -function MicrobeEditorHudSystem:menuButtonClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - print("played sound") - self.gameState.guiWindow:getChild("PauseMenu"):show() - self.gameState.guiWindow:getChild("PauseMenu"):moveToFront() - Engine:pauseGame() - self.menuOpen = true -end - -function MicrobeEditorHudSystem:resumeButtonClicked() - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("button-hover-click") - print("played sound") - self.gameState.guiWindow:getChild("PauseMenu"):hide() - Engine:resumeGame() - self.menuOpen = false -end diff --git a/scripts/microbe_editor/setup.as b/scripts/microbe_editor/setup.as new file mode 100644 index 00000000000..eb19927f0fd --- /dev/null +++ b/scripts/microbe_editor/setup.as @@ -0,0 +1,106 @@ +#include "microbe_editor_hud.as" + +// Called from ThriveGame when the editor has been entered and it should be setup +void onEditorEntry(MicrobeEditorWorld@ world){ + + LOG_INFO("Running microbe editor script setup"); + + world.RegisterScriptSystem("MicrobeEditorHudSystem", MicrobeEditorHudSystem()); + + + setupBackground(world); + setupCamera(world); + setupSound(world); +} + + +void setupBackground(MicrobeEditorWorld@ world){ + + LOG_ERROR("TODO: editor setupBackground"); + + // auto entity = Entity("background", MicrobeEditorWorld@) + // auto skyplane = SkyPlaneComponent(); + // skyplane.properties.plane.normal = Vector3(0, 0, 2000); + // skyplane.properties.materialName = "background/blue_01"; + // skyplane.properties.scale = 4; + // skyplane.properties.touch(); + // entity.addComponent(skyplane); + // //Create floating arrow entity + // entity = Entity("directionarrow", MicrobeEditorWorld@); + // auto sceneNode = OgreSceneNodeComponent(); + // sceneNode.meshName = "arrow.mesh"; + // sceneNode.transform.position = Vector3(0,7,-4); + // sceneNode.transform.orientation = Quaternion(Radian(Degree(90)), Vector3(1, 1, 1)); + // sceneNode.transform.scale = Vector3(0.5,0.5,0.5); + // sceneNode.transform.touch(); + // sceneNode.playAnimation("Stand", true); + // entity.addComponent(sceneNode); +} + +void setupCamera(MicrobeEditorWorld@ world){ + + LOG_ERROR("TODO: editor setupCamera"); + + // auto entity = Entity(CAMERA_NAME .. "3", MicrobeEditorWorld@); + // //Camera + // auto camera = OgreCameraComponent("camera3"); + // camera.properties.nearClipDistance = 5; + // camera.properties.orthographicalMode = true; + // camera.properties.fovY = Degree(30.0); + // camera.properties.touch(); + // entity.addComponent(camera); + // //Scene node + // auto sceneNode = OgreSceneNodeComponent(); + // sceneNode.transform.position.z = 30; + // sceneNode.transform.position.y = -3; + // sceneNode.transform.touch(); + // entity.addComponent(sceneNode); + // //Light + // auto light = OgreLightComponent(); + // light.setRange(200); + // entity.addComponent(light); + // //Workspace + // auto workspaceEntity = Entity(gameState.wrapper); + // auto workspaceComponent = OgreWorkspaceComponent("thrive_default"); + // workspaceComponent.properties.cameraEntity = entity; + // workspaceComponent.properties.position = 0; + // workspaceComponent.properties.touch(); + // workspaceEntity.addComponent(workspaceComponent); +} + +void setupSound(MicrobeEditorWorld@ world){ + + LOG_ERROR("TODO: editor setupSound"); + + // auto ambientEntity = Entity("editor_ambience", MicrobeEditorWorld@); + // auto soundSource = SoundSourceComponent(); + // soundSource.autoLoop = true; + // soundSource.ambientSoundSource = true; + // soundSource.volumeMultiplier = 0.6; + // ambientEntity.addComponent(soundSource); + + // //Sound + // soundSource.addSound("microbe-editor-theme-1", "microbe-editor-theme-1.ogg"); + // soundSource.addSound("microbe-editor-theme-2", "microbe-editor-theme-2.ogg"); + // soundSource.addSound("microbe-editor-theme-3", "microbe-editor-theme-3.ogg"); + // soundSource.addSound("microbe-editor-theme-4", "microbe-editor-theme-4.ogg"); + // soundSource.addSound("microbe-editor-theme-5", "microbe-editor-theme-5.ogg"); + // //Gui effects + // auto guiSoundEntity = Entity("gui_sounds", MicrobeEditorWorld@); + // soundSource = SoundSourceComponent(); + // soundSource.ambientSoundSource = true; + // soundSource.autoLoop = false; + // soundSource.volumeMultiplier = 1.0; + // guiSoundEntity.addComponent(soundSource); + // //Sound + // soundSource.addSound("button-hover-click", "soundeffects/gui/button-hover-click.ogg"); + + // auto ambientEntity2 = Entity("editor_ambience2", MicrobeEditorWorld@); + // auto soundSource2 = SoundSourceComponent(); + // soundSource2.volumeMultiplier = 0.1; + // soundSource2.ambientSoundSource = true; + // soundSource2.addSound("microbe-ambient", "soundeffects/microbe-ambience.ogg"); + // soundSource2.autoLoop = true; + // ambientEntity2.addComponent(soundSource2); +} + diff --git a/scripts/microbe_editor/setup.lua b/scripts/microbe_editor/setup.lua deleted file mode 100644 index 414316ba4e8..00000000000 --- a/scripts/microbe_editor/setup.lua +++ /dev/null @@ -1,115 +0,0 @@ - -local function setupBackground(gameState) - local entity = Entity.new("background", gameState.wrapper) - local skyplane = SkyPlaneComponent.new() - skyplane.properties.plane.normal = Vector3(0, 0, 2000) - skyplane.properties.materialName = "background/blue_01" - skyplane.properties.scale = 4 - skyplane.properties:touch() - entity:addComponent(skyplane) - -- Create floating arrow entity - entity = Entity.new("directionarrow", gameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.meshName = "arrow.mesh" - sceneNode.transform.position = Vector3(0,7,-4) - sceneNode.transform.orientation = Quaternion.new(Radian.new(Degree(90)), Vector3(1, 1, 1)) - sceneNode.transform.scale = Vector3(0.5,0.5,0.5) - sceneNode.transform:touch() - sceneNode:playAnimation("Stand", true) - entity:addComponent(sceneNode) -end - -local function setupCamera(gameState) - local entity = Entity.new(CAMERA_NAME .. "3", gameState.wrapper) - -- Camera - local camera = OgreCameraComponent.new("camera3") - camera.properties.nearClipDistance = 5 - camera.properties.orthographicalMode = true - camera.properties.fovY = Degree(30.0) - camera.properties:touch() - entity:addComponent(camera) - -- Scene node - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.transform.position.z = 30 - sceneNode.transform.position.y = -3 - sceneNode.transform:touch() - entity:addComponent(sceneNode) - -- Light - local light = OgreLightComponent.new() - light:setRange(200) - entity:addComponent(light) - -- Workspace - local workspaceEntity = Entity.new(gameState.wrapper) - local workspaceComponent = OgreWorkspaceComponent.new("thrive_default") - workspaceComponent.properties.cameraEntity = entity - workspaceComponent.properties.position = 0 - workspaceComponent.properties:touch() - workspaceEntity:addComponent(workspaceComponent) -end - -local function setupSound(gameState) - local ambientEntity = Entity.new("editor_ambience", gameState.wrapper) - local soundSource = SoundSourceComponent.new() - soundSource.autoLoop = true - soundSource.ambientSoundSource = true - soundSource.volumeMultiplier = 0.6 - ambientEntity:addComponent(soundSource) - - -- Sound - soundSource:addSound("microbe-editor-theme-1", "microbe-editor-theme-1.ogg") - soundSource:addSound("microbe-editor-theme-2", "microbe-editor-theme-2.ogg") - soundSource:addSound("microbe-editor-theme-3", "microbe-editor-theme-3.ogg") - soundSource:addSound("microbe-editor-theme-4", "microbe-editor-theme-4.ogg") - soundSource:addSound("microbe-editor-theme-5", "microbe-editor-theme-5.ogg") - -- Gui effects - local guiSoundEntity = Entity.new("gui_sounds", gameState.wrapper) - soundSource = SoundSourceComponent.new() - soundSource.ambientSoundSource = true - soundSource.autoLoop = false - soundSource.volumeMultiplier = 1.0 - guiSoundEntity:addComponent(soundSource) - -- Sound - soundSource:addSound("button-hover-click", "soundeffects/gui/button-hover-click.ogg") - - local ambientEntity2 = Entity.new("editor_ambience2", gameState.wrapper) - local soundSource2 = SoundSourceComponent.new() - soundSource2.volumeMultiplier = 0.1 - soundSource2.ambientSoundSource = true - soundSource2:addSound("microbe-ambient", "soundeffects/microbe-ambience.ogg") - soundSource2.autoLoop = true - ambientEntity2:addComponent(soundSource2) -end - -local function createMicrobeEditor(name) - - return g_luaEngine:createGameState( - name, - { - -- MicrobeSystem.new(), - MicrobeEditorHudSystem.new(), - -- Graphics - OgreAddSceneNodeSystem.new(), - OgreUpdateSceneNodeSystem.new(), - OgreCameraSystem.new(), - OgreLightSystem.new(), - SkySystem.new(), - OgreWorkspaceSystem.new(), - OgreRemoveSceneNodeSystem.new(), - RenderSystem.new(), - -- Other - SoundSourceSystem.new(), - }, - -- TODO: check whether physics is required in the editor - true, - "MicrobeEditor", - function(gameState) - setupBackground(gameState) - setupCamera(gameState) - setupSound(gameState) - end - ) -end - -GameState.MICROBE_EDITOR = createMicrobeEditor("microbe_editor") - ---Engine:setCurrentGameState(GameState.MICROBE_EDITOR) diff --git a/scripts/microbe_stage/agent_vacuole.as b/scripts/microbe_stage/agent_vacuole.as new file mode 100644 index 00000000000..3bc8dbcfd56 --- /dev/null +++ b/scripts/microbe_stage/agent_vacuole.as @@ -0,0 +1,70 @@ +#include "organelle_component.as" + +//////////////////////////////////////////////////////////////////////////////// +// Class for Organelles capable of producing and storing agents +//////////////////////////////////////////////////////////////////////////////// +class AgentVacuole : OrganelleComponent{ + + // Constructor + // + // @param compound + // The agent this organelle produces. + // + // @param process + // The process that creates the agent this organelle produces. + AgentVacuole(const string &in compound, const string &in process){ + + // Stored as a string as we only need it for dictionary operations + this.compound = formatUInt( + SimulationParameters::compoundRegistry().getTypeId(compound)); + this.process = process; + } + + void + onAddedToMicrobe( + ObjectID microbeEntity, + int q, int r, int rotation, + PlacedOrganelle@ organelle + ) override { + + MicrobeComponent@ microbeComponent = cast( + organelle.world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + if(!microbeComponent.specialStorageOrganelles.exists(compound)){ + microbeComponent.specialStorageOrganelles[compound] = 1; + } else { + auto value = microbeComponent.specialStorageOrganelles[compound]; + value = int(value) + 1; + } + } + + void + onRemovedFromMicrobe( + ObjectID microbeEntity, + PlacedOrganelle@ organelle + ) override { + + MicrobeComponent@ microbeComponent = cast( + organelle.world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto value = microbeComponent.specialStorageOrganelles[compound]; + value = int(value) - 1; + } + + // void AgentVacuole.storage(){ + // auto storage = StorageContainer() + // storage.set("compoundId", this.compoundId) + // storage.set("q", this.position.q) + // storage.set("r", this.position.r) + // return storage + // } + + // void AgentVacuole.load(storage){ + // this.compoundId = storage.get("compoundId", 0) + // this.position = {} + // this.position.q = storage.get("q", 0) + // this.position.r = storage.get("r", 0) + // } + + private string compound; + private string process; +} diff --git a/scripts/microbe_stage/agent_vacuole.lua b/scripts/microbe_stage/agent_vacuole.lua deleted file mode 100644 index 0d6f8e5513b..00000000000 --- a/scripts/microbe_stage/agent_vacuole.lua +++ /dev/null @@ -1,62 +0,0 @@ --------------------------------------------------------------------------------- --- Class for Organelles capable of producing and storing agents --------------------------------------------------------------------------------- -AgentVacuole = class( - OrganelleComponent, - -- Constructor - -- - -- @param arguments.process - -- The process that creates the agent this organelle produces. - -- - -- @param arguments.compound - -- The agent this organelle produces. - function(self, arguments, data) - - OrganelleComponent.create(self, arguments, data) - - --making sure this doesn't run when load() is called - if arguments == nil and data == nil then - return - end - - self.position = {} - self.position.q = data.q - self.position.r = data.r - self.compoundId = CompoundRegistry.getCompoundId(arguments.compound) - end -) - --- See organelle_component.lua for more information about the --- organelle component methods and the arguments they receive. - --- Overridded from ProcessOrganelle:onAddedToMicrobe -function AgentVacuole:onAddedToMicrobe(microbeEntity, q, r, rotation, organelle) - OrganelleComponent.onAddedToMicrobe(self, microbeEntity, q, r, rotation, organelle) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - if microbeComponent.specialStorageOrganelles[self.compoundId] == nil then - microbeComponent.specialStorageOrganelles[self.compoundId] = 1 - else - microbeComponent.specialStorageOrganelles[self.compoundId] = microbeComponent.specialStorageOrganelles[self.compoundId] + 1 - end -end - --- Overridded from ProcessOrganelle:onRemovedFromMicrobe -function AgentVacuole:onRemovedFromMicrobe(microbeEntity, q, r) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - microbeComponent.specialStorageOrganelles[self.compoundId] = microbeComponent.specialStorageOrganelles[self.compoundId] - 1 -end - -function AgentVacuole:storage() - local storage = StorageContainer.new() - storage:set("compoundId", self.compoundId) - storage:set("q", self.position.q) - storage:set("r", self.position.r) - return storage -end - -function AgentVacuole:load(storage) - self.compoundId = storage:get("compoundId", 0) - self.position = {} - self.position.q = storage:get("q", 0) - self.position.r = storage:get("r", 0) -end diff --git a/scripts/microbe_stage/agents.as b/scripts/microbe_stage/agents.as new file mode 100644 index 00000000000..32dc4c2bd8f --- /dev/null +++ b/scripts/microbe_stage/agents.as @@ -0,0 +1,43 @@ +const auto AGENT_EMISSION_VELOCITY = 20; + + +interface AgentEffect{ + + void applyEffect(); +} + + +class Agent{ + + Agent(string name, float weight, string mesh, float size, AgentEffect@ effect){ + + this.name = name; + this.weight = weight; + this.mesh = mesh; + this.size = size; + @this.effect = @effect; + } + + string name; + float weight; + string mesh; + float size; + AgentEffect@ effect; +} + +class OxytoxyEffect : AgentEffect{ + + void applyEffect(){ + + } +} + + +const dictionary AGENTS = { + {"oxytoxy", Agent("OxyToxy NT", 1, "oxytoxy.mesh", 0.3, OxytoxyEffect())} +}; + + + + + diff --git a/scripts/microbe_stage/bacteria_system.lua b/scripts/microbe_stage/bacteria_system.lua deleted file mode 100644 index 58e913afd4e..00000000000 --- a/scripts/microbe_stage/bacteria_system.lua +++ /dev/null @@ -1,270 +0,0 @@ --- BacteriaComponent: bacterial analogue to MicrobeComponent - -BacteriaComponent = class( - function(self, speciesName, health) - self.speciesName = speciesName - self.invincibility_timer = 0 - self.health = health - end -) - -BacteriaComponent.TYPE_NAME = "BacteriaComponent" - -function BacteriaComponent:load(storage) - self.speciesName = storage:get("speciesName", "Rickettsia") - self.invincibility_timer = storage:get("invincibility_timer", 0) - self.health = storage:get("health", 1) -end - -function BacteriaComponent:storage() - storage = StorageContainer.new() - storage:set("speciesName", self.speciesName) - storage:set("invincibility_timer", self.invincibility_timer) - storage:set("health", self.health) - return storage -end - -REGISTER_COMPONENT("BacteriaComponent", BacteriaComponent) - - -function initBacterialSpecies(gameState) - for name, data in pairs(bacteriaTable) do - local speciesEntity = Entity.new(name, gameState.wrapper) - local processorComponent = ProcessorComponent.new() - for process, capacity in pairs(data.processes) do - processorComponent:setCapacity(BioProcessRegistry.getId(process), capacity) - end - speciesEntity:addComponent(processorComponent) - end -end - --- Bacterium: Entity wrapper for a bacterium - -Bacterium = class( - function(self, entity) - self.entity = entity - local all_components_available = true - for key, cType in pairs(Bacterium.COMPONENTS) do - local component = getComponent(entity, cType) - if component == nil then - print("entity is missing component: " .. key) - all_components_available = false - end - self[key] = component - end - assert(all_components_available, "Can't create bacterium from this entity") - end -) - -Bacterium.COMPONENTS = { - compoundBag = CompoundBagComponent, - bacterium = BacteriaComponent, - rigidBody = RigidBodyComponent, - sceneNode = OgreSceneNodeComponent, - collisionHandler = CollisionComponent, -} - -function Bacterium.createBacterium(speciesName, pos, gameState) - local entity = Entity.new(gameState.wrapper) - local species_data = bacteriaTable[speciesName] - local bacteriaComponent = BacteriaComponent.new(speciesName, - bacteriaTable[speciesName].health) - - local rigidBody = RigidBodyComponent.new() - rigidBody.properties.shape = SphereShape.new(HEX_SIZE) - rigidBody.properties.mass = bacteriaTable[speciesName].mass - rigidBody.properties.friction = 0.2 - rigidBody.properties.linearDamping = 0.8 - rigidBody:setDynamicProperties( - pos, - Quaternion.new(Radian.new(Degree(math.random()*360)), Vector3(0, 0, 1)), - Vector3(0, 0, 0), - Vector3(0, 0, 0) - ) - rigidBody.properties:touch() - - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.meshName = species_data.mesh - sceneNode.visible = true - sceneNode.transform.scale = Vector3(1, 1, 1) - sceneNode.transform.position = pos - sceneNode.transform:touch() - - local compoundBag = CompoundBagComponent.new() - compoundBag.storageSpace = species_data.capacity - for compound, amount in pairs(species_data.compounds) do - compoundBag:giveCompound(CompoundRegistry.getCompoundId(compound), amount) - end - compoundBag:setProcessor(getComponent(speciesName, gameState, ProcessorComponent)) - - local reactionHandler = CollisionComponent.new() - reactionHandler:addCollisionGroup("bacteria") - - local components = { - bacteriaComponent, - rigidBody, - sceneNode, - compoundBag, - reactionHandler, - } - - for _, component in ipairs(components) do - entity:addComponent(component) - end - - local bacterium = Bacterium(entity) - return entity -end - -function Bacterium:purgeCompounds() - local compoundAmountToDump = self.compoundBag:getStorageSpaceUsed() - self.compoundBag.storageSpace - - -- Dumping all the useless compounds (with price = 0). - for _, compoundId in pairs(CompoundRegistry.getCompoundList()) do - local price = self.compoundBag:getPrice(compoundId) - if price <= 0 then - local amount = self.compoundBag:getCompoundAmount(compoundId) - if amount > 0 then - local amountToEject = self.compoundBag:takeCompound(compoundId, amount) - self:ejectCompound(compoundId, amountToEject) - end - end - end - - if compoundAmountToDump > 0 then - --Calculating each compound price to dump proportionally. - local compoundPrices = {} - local priceSum = 0 - for _, compoundId in pairs(CompoundRegistry.getCompoundList()) do - local amount = getComponent(self.entity, CompoundBagComponent) - :getCompoundAmount(compoundId) - - if amount > 0 then - local price = self.compoundBag:getPrice(compoundId) - compoundPrices[compoundId] = price - priceSum = priceSum + price - end - end - - --Dumping each compound according to it's price. - for compoundId, price in pairs(compoundPrices) do - local amountToEject = compoundAmountToDump * price / priceSum - if amount > 0 then amountToEject = self.compoundBag:takeCompound(compoundId, amountToEject) end - if amount > 0 then self:ejectCompound(compoundId, amountToEject) end - end - end -end - -function Bacterium:ejectCompound(compoundId, amount) - createCompoundCloud(CompoundRegistry.getCompoundInternalName(compoundId), - self.sceneNode.transform.position.x, - self.sceneNode.transform.position.y, - amount * 5000) -end - -Bacterium.INVINCIBILITY_TIME = 250 - -function Bacterium:damage(amount) - if self.bacterium.invincibility_timer > 0 then return end - self.bacterium.health = self.bacterium.health - amount - if self.bacterium.health < 0 then - self:kill() - end - self.bacterium.invincibility_timer = Bacterium.INVINCIBILITY_TIME -end - -function Bacterium:kill() - local compoundsToRelease = {} - - for _, compoundId in pairs(CompoundRegistry.getCompoundList()) do - local total = self.compoundBag:getCompoundAmount(compoundId) - local ejectedAmount = self.compoundBag:takeCompound(compoundId, total) - compoundsToRelease[compoundId] = ejectedAmount - end - - -- todo: add compounds locked in bacterium - - for compoundId, amount in pairs(compoundsToRelease) do - self:ejectCompound(compoundId, amount) - end - - -- Releasing the organelle if needed. - local speciesName = self.bacterium.speciesName - if bacteriaTable[speciesName].organelle ~= nil then - local organelleName = bacteriaTable[speciesName].organelle - - -- Creating a powerup entity - local powerupEntity = Entity.new(g_luaEngine.currentGameState.wrapper) - setSpawnablePhysics(powerupEntity, self.sceneNode.transform.position, - organelleTable[organelleName].mesh, 0.9, SphereShape.new(HEX_SIZE)) - - local reactionHandler = CollisionComponent.new() - reactionHandler:addCollisionGroup("powerup") - powerupEntity:addComponent(reactionHandler) - - local powerupComponent = PowerupComponent.new() - -- Function name must be in configs.lua - powerupComponent:setEffect(organelleName .. "Effect") - powerupEntity:addComponent(powerupComponent) - end - - self.entity:destroy() -end - -function Bacterium:update(logicTime) - self:purgeCompounds() - if self.bacterium.invincibility_timer > 0 then - self.bacterium.invincibility_timer = self.bacterium.invincibility_timer - logicTime - end -end - --- BacteriaSystem - -BacteriaSystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - - self.entities = EntityFilter.new( - { - BacteriaComponent, - OgreSceneNodeComponent, - RigidBodyComponent, - CollisionComponent - }, - true - ) - - self.bacteria = {} - end -) - -function BacteriaSystem:init(gameState) - LuaSystem.init(self, "BacteriaSystem", gameState) - self.entities:init(gameState.wrapper) -end - - -function BacteriaSystem:shutdown() - LuaSystem.shutdown(self) - self.entities:shutdown() -end - - -function BacteriaSystem:update(renderTime, logicTime) - for _, entityId in pairs(self.entities:removedEntities()) do - self.bacteria[entityId] = nil - end - for _, entityId in pairs(self.entities:addedEntities()) do - local bacterium = Bacterium(Entity.new(entityId, self.gameState.wrapper)) - self.bacteria[entityId] = bacterium - end - self.entities:clearChanges() - for _, bacterium in pairs(self.bacteria) do - bacterium:update(logicTime) - end -end - - - diff --git a/scripts/microbe_stage/bacteria_table.lua b/scripts/microbe_stage/bacteria_table.lua deleted file mode 100644 index e04e2b4c8bb..00000000000 --- a/scripts/microbe_stage/bacteria_table.lua +++ /dev/null @@ -1,33 +0,0 @@ -bacteriaTable = { - ["Rickettsia"] = { - mesh = "mitochondrion.mesh", - processes = { - -- This should probably be something else? - ["Photosynthesis"] = 0.6, - }, - - compounds = { - ["co2"] = 80, - }, - - capacity = 50, - mass = 0.4, - health = 10 - }, - - ["Cyanobacteria"] = { - mesh = "chloroplast.mesh", - processes = { - ["Photosynthesis"] = 0.6, - }, - - compounds = { - ["co2"] = 80, - }, - - capacity = 50, - mass = 0.4, - health = 10, - organelle = "chloroplast" - } -} diff --git a/scripts/microbe_stage/biome.as b/scripts/microbe_stage/biome.as new file mode 100644 index 00000000000..b77e4426c4f --- /dev/null +++ b/scripts/microbe_stage/biome.as @@ -0,0 +1,117 @@ +//Global table which stores the current biome the player is in. +uint64 currentBiome = 0; + +const Biome@ getCurrentBiome(){ + + return SimulationParameters::biomeRegistry().getTypeData(currentBiome); +} + +ObjectID createCompoundCloud(CellStageWorld@ world, CompoundId compound, + float x, float z, float amount +) { + if(amount == 0){ + amount = getCurrentBiome().getCompound(compound).amount; + } + + // This is just a sanity check + //if(compoundTable[compoundName] and compoundTable[compoundName].isCloud) + + // addCloud requires integer arguments + int roundedX = round(x); + int roundedZ = round(z); + + // TODO: this isn't the best way to handle this for max performance + world.GetCompoundCloudSystem().addCloud(compound, amount, roundedX, roundedZ); + + // We don't spawn new entities + return NULL_OBJECT; +} + +class CloudFactory{ + + CloudFactory(CompoundId c){ + + compound = c; + } + + ObjectID spawn(CellStageWorld@ world, Float3 pos){ + + return createCompoundCloud(world, compound, pos.X, pos.Z, 0); + } + + private CompoundId compound; +} + +dictionary compoundSpawnTypes; + +//Setting the current biome to the one with the specified name. +void setBiome(uint64 biomeId, CellStageWorld@ world){ + assert(world !is null, "setBiome requires world"); + + LOG_INFO("setting biome to: " + biomeId); + //Getting the base biome to change to. + currentBiome = biomeId; + + auto biome = getCurrentBiome(); + + auto biomeCompounds = biome.getCompoundKeys(); + LOG_INFO("biomeCompounds.length = " + biomeCompounds.length()); + for(uint i = 0; i < biomeCompounds.length(); ++i){ + auto compoundId = biomeCompounds[i]; + + if(SimulationParameters::compoundRegistry().getTypeData(compoundId).isCloud){ + + CloudFactory@ spawnCloud = CloudFactory(compoundId); + + const string typeStr = formatUInt(compoundId); + + // Remove existing (if there is one) + if(compoundSpawnTypes.exists(typeStr)){ + world.GetSpawnSystem().removeSpawnType(SpawnerTypeId( + compoundSpawnTypes[typeStr])); + } + + // And register new + + LOG_INFO("registering cloud: " + compoundId); + + SpawnFactoryFunc@ factory = SpawnFactoryFunc(spawnCloud.spawn); + + compoundSpawnTypes[typeStr] = world.GetSpawnSystem().addSpawnType( + factory, biome.getCompound(biomeCompounds[i]).density, + CLOUD_SPAWN_RADIUS); + } + } + //change the lighting + setSunlightForBiome(world); + //Changing the background. + GetThriveGame().setBackgroundMaterial(biome.background); +} + +void setSunlightForBiome(CellStageWorld@ world){ + //light properties isnt working for some reason + world.SetLightProperties(getCurrentBiome().diffuseColors, getCurrentBiome().specularColors, + Ogre::Vector3(Float3(0.55f, -0.3f, 0.75f).Normalize()), 30, + // https://ogrecave.github.io/ogre/api/2.1/class_ogre_1_1_scene_manager.html#a56cd9aa2c4dee4eec9eb07ce1372fb52 + Ogre::ColourValue(0.3f, 0.3f, 0.3f), + Ogre::ColourValue(0.2f, 0.2f, 0.2f), + -Float3(0.55f, -0.3f, 0.75f).Normalize() + Float3::UnitVUp * 0.2f + ); + //these work fine + LOG_INFO("Diffuse Colours For Biome r:" + getCurrentBiome().diffuseColors.r + + "g:" + getCurrentBiome().diffuseColors.g + "b:" + getCurrentBiome().diffuseColors.b); + LOG_INFO("specular COlours For Biome r:" + getCurrentBiome().diffuseColors.r + + "g:" + getCurrentBiome().specularColors.g + "b:" + getCurrentBiome().specularColors.b); +} + +//Setting the current biome to a random biome selected from the biome table. +void setRandomBiome(CellStageWorld@ world){ + LOG_INFO("setting random biome"); + //Getting the size of the biome table. + //Selecting a random biome. + auto biome = GetEngine().GetRandom().GetNumber(0, + int(SimulationParameters::biomeRegistry().getSize())); + + //Switching to that biome. + setBiome(biome, world); +} diff --git a/scripts/microbe_stage/biome.lua b/scripts/microbe_stage/biome.lua deleted file mode 100644 index 0fff880155b..00000000000 --- a/scripts/microbe_stage/biome.lua +++ /dev/null @@ -1,59 +0,0 @@ ---Global table which stores the current biome the player is in. -currentBiome = {} - ---Setting the current biome to the one with the specified name. -function setBiome(biomeName, gameState) - assert(gameState ~= nil, "setBiome requires gameState") - - --Getting the base biome to change to. - local baseBiome = biomeTable[biomeName] - - --Setting the new biome attributes - currentBiome = {} - currentBiome.name = biomeName - currentBiome.temperature = baseBiome.temperature - currentBiome.sunlight = baseBiome.sunlight - currentBiome.background = baseBiome.background - currentBiome.compounds = {} - - for compoundName, compoundData in pairs(baseBiome.compounds) do - currentBiome.compounds[compoundName] = compoundData.amount - - if compoundTable[compoundName].isCloud then - local spawnCloud = function(pos) - return createCompoundCloud(compoundName, pos.x, pos.y) - end - - gSpawnSystem:removeSpawnType(compoundSpawnTypes[compoundName]) - compoundSpawnTypes[compoundName] = gSpawnSystem:addSpawnType(spawnCloud, compoundData.density, CLOUD_SPAWN_RADIUS) - end - end - - --Changing the background. - local entity = Entity.new("background", gameState.wrapper) - local skyplane = SkyPlaneComponent.new() - skyplane.properties.plane.normal = Vector3(0, 0, 2000) - skyplane.properties.materialName = currentBiome.background - skyplane.properties.scale = 200 - skyplane.properties:touch() - entity:addComponent(skyplane) -end - ---Setting the current biome to a random biome selected from the biome table. -function setRandomBiome(gameState) - --Getting the size of the biome table. - local numberOfBiomes = 0 - local biomeNameTable = {} - for biomeName, _ in pairs(biomeTable) do - numberOfBiomes = numberOfBiomes + 1 - table.insert(biomeNameTable, biomeName) - end - - --Selecting a random biome. - math.randomseed(os.time()) - local rand = math.random(1, numberOfBiomes) - local currentBiomeName = biomeNameTable[rand] - - --Switching to that biome. - setBiome(currentBiomeName, gameState) -end diff --git a/scripts/microbe_stage/biome_table.lua b/scripts/microbe_stage/biome_table.lua deleted file mode 100644 index 49e76c5c1ac..00000000000 --- a/scripts/microbe_stage/biome_table.lua +++ /dev/null @@ -1,79 +0,0 @@ ---[[ -Biome atributes: - temperature: The average temperature of the biome. - Measured in celsius degrees. - - sunlight: Percentage of sunligth that reaches the biome. - - background: Name of the background material used in this biome. - - compounds: Table with the amount of each compound in the biome. -]] - -biomeTable = { - ["default"] = { --Where would this biome be anyways? - temperature = 30, - sunlight = 75, - background = "Background", - compounds = { - oxygen = {amount = 65000, density = 1/5000}, - co2 = {amount = 65000, density = 1/5000}, - ammonia = {amount = 65000, density = 1/5000}, - glucose = {amount = 65000, density = 1/5000} - }, - - bacteria = { - Rickettsia = 20 - } - }, - - ["volcanic_vent"] = { - temperature = 100, - sunlight = 40, - background = "Background_Vent", - compounds = { - oxygen = {amount = 60000, density = 1/5000}, - co2 = {amount = 100000, density = 1/5000}, - ammonia = {amount = 85000, density = 1/5000}, - glucose = {amount = 65000, density = 1/5000} - }, - - bacteria = { - Rickettsia = 20 - } - }, - - ["abyss"] = { - temperature = 35, - sunlight = 5, - background = "Background_Abyss", - compounds = { - oxygen = {amount = 50000, density = 1/5000}, - co2 = {amount = 70000, density = 1/5000}, - ammonia = {amount = 70000, density = 1/5000}, - glucose = {amount = 80000, density = 1/5000} - }, - - bacteria = { - Rickettsia = 20 - } - }, - - ["shallow"] = { - temperature = 25, - sunlight = 90, - background = "Background_Shallow", - compounds = { - oxygen = {amount = 100000, density = 1/5000}, - co2 = {amount = 70000, density = 1/5000}, - ammonia = {amount = 60000, density = 1/5000}, - glucose = {amount = 70000, density = 1/5000} - }, - - bacteria = { - Rickettsia = 20 - } - } -} - ---TODO: check this numbers. diff --git a/scripts/microbe_stage/compound_table.lua b/scripts/microbe_stage/compound_table.lua deleted file mode 100644 index 473e2257d8f..00000000000 --- a/scripts/microbe_stage/compound_table.lua +++ /dev/null @@ -1,88 +0,0 @@ ---[[ -Compound atributes: - name: The name of the compound, used in the GUI. - - volume: The volume of an unit of compound. - - isCloud: Whether the compound forms clouds (maybe it should be checked - automatically in the biomes?). By default is false. - - colour: A table with the colour of the compound, used in the clouds and in the GUI. - - isUseful: Whether this compound has some use for microbes besides being transformed - into other compounds (i.e.: ATP is useful because the microbe spends it to move). -]] - -compoundTable = { - ["atp"] = { - name = "ATP", - volume = 1, - isUseful = true - }, - - ["oxygen"] = { - name = "Oxygen", - volume = 1, - isCloud = true, - - colour = { - r = 60, - g = 160, - b = 180 - } - }, - - ["aminoacids"] = { - name = "Amino Acids", - volume = 1, - isCloud = true, --Note that in the biome-table branch no aminoacid cloud would form. - isUseful = true, - - colour = { - r = 255, - g = 150, - b = 200 - } - }, - - ["ammonia"] = { - name = "Ammonia", - volume = 1, - isCloud = true, - - colour = { - r = 255, - g = 220, - b = 50 - } - }, - - ["glucose"] = { - name = "Glucose", - volume = 1, - isCloud = true, - - colour = { - r = 150, - g = 170, - b = 180 - } - }, - - ["co2"] = { - name = "CO2", - volume = 1, - isCloud = true, - - colour = { - r = 20, - g = 50, - b = 100 - } - }, - - ["fattyacids"] = { - name = "Fatty Acids", - volume = 1, - } -} \ No newline at end of file diff --git a/scripts/microbe_stage/configs.as b/scripts/microbe_stage/configs.as new file mode 100644 index 00000000000..b60bd1b375f --- /dev/null +++ b/scripts/microbe_stage/configs.as @@ -0,0 +1,211 @@ +// Holds config file contents, translated into AngelScript objects +#include "agents.as" +#include "organelle.as" + +// Global defines +const auto CLOUD_SPAWN_RADIUS = 75; + +const auto POWERUP_SPAWN_RADIUS = 85; + +const auto DEFAULT_SPAWN_DENSITY = 1/25000.f; + +const auto MIN_COLOR = 0.0f; +const auto MAX_COLOR = 0.8f; +const auto MIN_OPACITY = 0.3f; +const auto MAX_OPACITY = 4.0f; + +const auto MUTATION_CREATION_RATE = 0.1f; +const auto MUTATION_DELETION_RATE = 0.1f; + +const auto MICROBE_SPAWN_RADIUS = 85; +//bacteria get massively extra radius so they can spawn in proper colonies and act as landmarks +const auto BACTERIA_SPAWN_RADIUS = 185; + +const auto PLAYER_NAME = "Player"; + + +// TODO: move these into gamestate +// must be global +int chloroplast_Organelle_Number = 0; +int toxin_Organelle_Number = 0; +bool chloroplast_unlocked = false; +bool toxin_unlocked = false; + + +// this count the toxin Organelle Number +bool toxin_number(){ + toxin_Organelle_Number = toxin_Organelle_Number + 1; + LOG_WRITE("toxin_Organelle_Number: " + toxin_Organelle_Number); + if(toxin_Organelle_Number >= 3){ // 3 is an example + unlockToxinIfStillLocked(); + toxin_call_Notification(); + } + + return true; +} + +// this count the chloroplast Organelle Number +void chloroplast_number(){ + chloroplast_Organelle_Number = chloroplast_Organelle_Number + 1; + LOG_WRITE("chloroplast_Organelle_Number: " + chloroplast_Organelle_Number); + + if(chloroplast_Organelle_Number >= 3){ // 3 is an example + unlockChloroplastIfStillLocked(); + chloroplast_call_Notification(); + } +} + +void playOrganellePickupSound(){ + GetEngine().GetSoundDevice().Play2DSoundEffect("Data/Sound/microbe-pickup-organelle.ogg"); +} + +// TODO: remove this code duplication + +// this where the Unlock Happen +void unlockToxinIfStillLocked(){ + if(!GetThriveGame().playerData().lockedMap().isLocked("Toxin")) + return; + + showMessage("Toxin Unlocked!"); + GetThriveGame().playerData().lockedMap().unlock("Toxin"); + + playOrganellePickupSound(); +} + +//this where the Unlock Happen +void unlockChloroplastIfStillLocked(){ + + if(!GetThriveGame().playerData().lockedMap().isLocked("chloroplast")) + return; + + showMessage("Chloroplast Unlocked!"); + GetThriveGame().playerData().lockedMap().unlock("chloroplast"); + + playOrganellePickupSound(); +} + + +void chloroplast_call_Notification(){ + if(chloroplast_unlocked == false){ + // global_activeMicrobeStageHudSystem.chloroplastNotificationenable(); + GetEngine().GetEventHandler().CallEvent(GenericEvent("chloroplastNotificationenable")); + chloroplast_unlocked = true; + } +} + +void toxin_call_Notification(){ + if(toxin_unlocked == false){ + // global_activeMicrobeStageHudSystem.toxinNotificationenable(); + GetEngine().GetEventHandler().CallEvent(GenericEvent("toxinNotificationenable")); + toxin_unlocked = true; + } +} + +// TODO: move this to where axialToCartesian is defined +// We should use Int2 instead, or MAYBE a derived class defined in c++ if we wanna be really fancy... +/* +class AxialCoordinates{ + + AxialCoordinates(int q, int r){ + + this.q = q; + this.r = r; + } + + // q and r are radial coordinates instead of cartesian + int q; + int r; +} +*/ + +// Note this is an old comment +/* +Placing organelles can get downright annoying if you don't +map them out. To make it easier, download a few sheets of hexgrid +off the internet. Before you print them though, set up the axes +properly. See http://i.imgur.com/kTxHFMC.png for how. When you're +drawing out your microbe, keep in mind that it faces forward along +the +r direction. +0 degrees is considered up for the rotation (+r), and you can rotate +in 60 degree intervals counter clockwise. +The colour of the microbe should never be lower than (0.3, 0.3, 0.3) +*/ + +class OrganelleTemplatePlaced{ + + OrganelleTemplatePlaced(const string &in type, int q, int r, int rotation){ + + this.type = type; + this.q = q; + this.r = r; + this.rotation = rotation; + } + + string type; + int q; + int r; + int rotation; +} + +class MicrobeTemplate{ + + MicrobeTemplate( + float spawnDensity, + dictionary compounds, + array organelles, + Float4 colour + ) { + this.spawnDensity = spawnDensity; + this.compounds = compounds; + this.organelles = organelles; + this.colour = colour; + } + + float spawnDensity; + dictionary compounds; + array organelles; + Float4 colour; +} + +class InitialCompound{ + InitialCompound(){ + + this.amount = 0; + this.priority = 1; + } + + InitialCompound(float amount, int priority = 1){ + + this.amount = amount; + this.priority = priority; + } + + float amount; + int priority; +} + + +const dictionary STARTER_MICROBES = { + { + "Default", MicrobeTemplate(1/14000, + { + {"atp", InitialCompound(60)}, + {"glucose", InitialCompound(5)}, + {"oxygen", InitialCompound(10)} + }, + { + OrganelleTemplatePlaced("nucleus", 0, 0, 180), + OrganelleTemplatePlaced("mitochondrion", -1, 3, 240), + OrganelleTemplatePlaced("vacuole", 1, 2, 0), + OrganelleTemplatePlaced("flagellum", 1, 3, 0), + OrganelleTemplatePlaced("flagellum", -1, 4, 0) + }, + Float4(1, 1, 1, 1)) + } +}; + + + + + + diff --git a/scripts/microbe_stage/configs.lua b/scripts/microbe_stage/configs.lua deleted file mode 100644 index c462e60c515..00000000000 --- a/scripts/microbe_stage/configs.lua +++ /dev/null @@ -1,107 +0,0 @@ --- Holds config file contents, translated into lua table form - ---[[ -Style tips: -- Always indent, only with spaces, 4 spaces to an indent. -- Always leave trailing commas on the last elements of multiline tables - then, the next time something gets added, you don't need to change the line above - just keeps things cleaner. -- Always leave a trailing newline at the end of the file. - Google it, it is the right way to end text files. -]] - -agents = { - oxytoxy = { - name = "OxyToxy NT", - weight = 1, - mesh = "oxytoxy.mesh", - size = 0.3, - effect = oxytoxyEffect, - }, -} --- must be global -chloroplast_Organelle_Number = 0 -toxin_Organelle_Number = 0 -chloroplast_unlocked = false -toxin_unlocked = false - -function toxinEffect() - toxin_Organelle_Number = toxin_Organelle_Number + 1 - print (toxin_Organelle_Number) - if toxin_Organelle_Number >= 3 then -- 3 is an example - toxin_unlock() - toxin_call_Notification() - end - return true -end - -function toxin_unlock(entityId) - if Engine:playerData():lockedMap():isLocked("Toxin") then - showMessage("Toxin Unlocked!") - Engine:playerData():lockedMap():unlock("Toxin") - local guiSoundEntity = Entity("gui_sounds") - getComponent(guiSoundEntity, SoundSourceComponent):playSound("microbe-pickup-organelle") - end -end - -function chloroplastEffect() - chloroplast_Organelle_Number = chloroplast_Organelle_Number + 1 - if chloroplast_Organelle_Number >= 3 then -- 3 is an example - chloroplast_unlock() - chloroplast_call_Notification() - end - return true -end - -function chloroplast_unlock(entityId) - if Engine:playerData():lockedMap():isLocked("chloroplast") then - showMessage("Chloroplast Unlocked!") - Engine:playerData():lockedMap():unlock("chloroplast") - local guiSoundEntity = Entity("gui_sounds") - getComponent(guiSoundEntity, SoundSourceComponent):playSound("microbe-pickup-organelle") - end -end - -function chloroplast_call_Notification() - if chloroplast_unlocked == false then - global_activeMicrobeStageHudSystem:chloroplastNotificationenable() - chloroplast_unlocked = true - end -end -function toxin_call_Notification() - if toxin_unlocked == false then - global_activeMicrobeStageHudSystem:toxinNotificationenable() - toxin_unlocked = true - end -end - ---[[ -Placing organelles can get downright annoying if you don't -map them out. To make it easier, download a few sheets of hexgrid -off the internet. Before you print them though, set up the axes -properly. See http://i.imgur.com/kTxHFMC.png for how. When you're -drawing out your microbe, keep in mind that it faces forward along -the +r direction. -0 degrees is considered up for the rotation (+r), and you can rotate -in 60 degree intervals counter clockwise. -The colour of the microbe should never be lower than (0.3, 0.3, 0.3) -]] - -starter_microbes = { - Default = { - spawnDensity = 1/14000, - compounds = { - atp = {amount=60}, - glucose = {amount = 5}, - oxygen = {amount = 10} - }, - organelles = { - {name="nucleus",q=0,r=0, rotation=0}, - {name="mitochondrion",q=-1,r=-2, rotation=240}, - {name="vacuole",q=1,r=-3, rotation=0}, - {name="flagellum",q=-1,r=-3, rotation=0}, - {name="flagellum",q=1,r=-4, rotation=0}, - }, - colour = {r=1,g=1,b=1}, - }, -} diff --git a/scripts/microbe_stage/hex.as b/scripts/microbe_stage/hex.as new file mode 100644 index 00000000000..0d6adf157c9 --- /dev/null +++ b/scripts/microbe_stage/hex.as @@ -0,0 +1,89 @@ +// Defines some utility functions and tables related to hex grids +// +// For more information on hex grids, see www.redblobgames.com/grids/hexagons. +// +// We use flat-topped hexagons with axial coordinates. +// please note the coordinate system we use is horizontally symmetric to the one in the page + +// Size of a single hex, that is the distance from the center to a corner +const float HEX_SIZE = Hex::getHexSize(); + +// Enumeration of the hex sides, clock-wise +enum HEX_SIDE{ + TOP = 1, + TOP_RIGHT = 2, + BOTTOM_RIGHT = 3, + BOTTOM = 4, + BOTTOM_LEFT = 5, + TOP_LEFT = 6 +} + + +// Maps the HEX_SIDE enumeration to a human-readable name +const dictionary HEX_SIDE_NAME = { + {HEX_SIDE::TOP, "top"}, + {HEX_SIDE::TOP_RIGHT, "top_right"}, + {HEX_SIDE::BOTTOM_RIGHT, "bottom_right"}, + {HEX_SIDE::BOTTOM, "bottom"}, + {HEX_SIDE::BOTTOM_LEFT, "bottom_left"}, + {HEX_SIDE::TOP_LEFT, "top_left"} +}; + + +// Maps a hex side to its direct opposite +const dictionary OPPOSITE_HEX_SIDE = { + {HEX_SIDE::TOP, HEX_SIDE::BOTTOM}, + {HEX_SIDE::TOP_RIGHT, HEX_SIDE::BOTTOM_LEFT}, + {HEX_SIDE::BOTTOM_RIGHT, HEX_SIDE::TOP_LEFT}, + {HEX_SIDE::BOTTOM, HEX_SIDE::TOP}, + {HEX_SIDE::BOTTOM_LEFT, HEX_SIDE::TOP_RIGHT}, + {HEX_SIDE::TOP_LEFT, HEX_SIDE::BOTTOM_RIGHT} +}; + + +// Each hex has six neighbours, one for each side. This table maps the hex +// side to the coordinate offset of the neighbour adjacent to that side. +const dictionary HEX_NEIGHBOUR_OFFSET = { + {HEX_SIDE::TOP, Int2 = { 0, 1}}, + {HEX_SIDE::TOP_RIGHT, Int2 = { 1, 0}}, + {HEX_SIDE::BOTTOM_RIGHT, Int2 = { 1, -1}}, + {HEX_SIDE::BOTTOM, Int2 = { 0, -1}}, + {HEX_SIDE::BOTTOM_LEFT, Int2 = {-1, 0}}, + {HEX_SIDE::TOP_LEFT, Int2 = {-1, 1}} +}; + + +// // Returns an iterator that iterates over all six neighbours of a hex +// // +// // @param q, r +// // Coordinates of the center hex +// // +// // Example: +// // +// // for(side, q, r in iterateNeighbours(0, 0)){ +// // auto sideName = HEX_SIDE::NAME[side] +// // debug("Neighbour to " .. sideName .. ": " .. tostring(q) .. ", " .. tostring(r)) +// // } +// // +// // This would print the coordinates of each hex around the (0, 0) hexagon. +// // Not used? +// void iterateNeighbours(int q, int r){ + +// void nextNeighbour(int dummy, int i){ +// i = i+1; +// auto offset = HEX_NEIGHBOUR_OFFSET[i]; +// if(offset == null){ +// return null; +// } +// return i, q + offset[1], r + offset[2]; +// } +// return nextNeighbour(0, 0); +// } + +// Call Hex::axialToCartesian directly +// and also all the others that were here before +// This might need tweaking in places that call this: +// void cubeToAxial(x, y, z){ +// result = Hex.cubeToAxial(x, y, z); +// return result.x, result.y; +// } diff --git a/scripts/microbe_stage/hex.lua b/scripts/microbe_stage/hex.lua deleted file mode 100644 index 9cc8b94d7fc..00000000000 --- a/scripts/microbe_stage/hex.lua +++ /dev/null @@ -1,210 +0,0 @@ --- Defines some utility functions and tables related to hex grids --- --- For more information on hex grids, see www.redblobgames.com/grids/hexagons. --- --- We use flat-topped hexagons with axial coordinates. --- please note the coordinate system we use is horizontally symmetric to the one in the page - --- Size of a single hex, that is the distance from the center to a corner -HEX_SIZE = 0.75 -Hex.setHexSize(HEX_SIZE) - --- Enumeration of the hex sides, clock-wise -HEX_SIDE = { - TOP = 1, - TOP_RIGHT = 2, - BOTTOM_RIGHT = 3, - BOTTOM = 4, - BOTTOM_LEFT = 5, - TOP_LEFT = 6 -} - - --- Maps the HEX_SIDE enumeration to a human-readable name -HEX_SIDE_NAME = { - [HEX_SIDE.TOP] = "top", - [HEX_SIDE.TOP_RIGHT] = "top_right", - [HEX_SIDE.BOTTOM_RIGHT] = "bottom_right", - [HEX_SIDE.BOTTOM] = "bottom", - [HEX_SIDE.BOTTOM_LEFT] = "bottom_left", - [HEX_SIDE.TOP_LEFT] = "top_left", -} - - --- Maps a hex side to its direct opposite -OPPOSITE_HEX_SIDE = { - [HEX_SIDE.TOP] = HEX_SIDE.BOTTOM, - [HEX_SIDE.TOP_RIGHT] = HEX_SIDE.BOTTOM_LEFT, - [HEX_SIDE.BOTTOM_RIGHT] = HEX_SIDE.TOP_LEFT, - [HEX_SIDE.BOTTOM] = HEX_SIDE.TOP, - [HEX_SIDE.BOTTOM_LEFT] = HEX_SIDE.TOP_RIGHT, - [HEX_SIDE.TOP_LEFT] = HEX_SIDE.BOTTOM_RIGHT, -} - - --- Each hex has six neighbours, one for each side. This table maps the hex --- side to the coordinate offset of the neighbour adjacent to that side. -HEX_NEIGHBOUR_OFFSET = { - [HEX_SIDE.TOP] = { 0, 1}, - [HEX_SIDE.TOP_RIGHT] = { 1, 0}, - [HEX_SIDE.BOTTOM_RIGHT] = { 1, -1}, - [HEX_SIDE.BOTTOM] = { 0, -1}, - [HEX_SIDE.BOTTOM_LEFT] = {-1, 0}, - [HEX_SIDE.TOP_LEFT] = {-1, 1} -} - - --- Returns an iterator that iterates over all six neighbours of a hex --- --- @param q, r --- Coordinates of the center hex --- --- Example: --- --- for side, q, r in iterateNeighbours(0, 0) do --- local sideName = HEX_SIDE_NAME[side] --- debug("Neighbour to " .. sideName .. ": " .. tostring(q) .. ", " .. tostring(r)) --- end --- --- This would print the coordinates of each hex around the (0, 0) hexagon. - --- Not used? -function iterateNeighbours(q, r) - local function nextNeighbour(dummy, i) - i = i+1 - local offset = HEX_NEIGHBOUR_OFFSET[i] - if offset == nil then - return nil - end - return i, q + offset[1], r + offset[2] - end - return nextNeighbour, 0, 0 -end - - --- Converts axial hex coordinates to cartesian coordinates --- --- The result is the position of the hex at q, r --- --- @param q, r --- Hex coordinates --- --- @returns x, y --- Cartesian coordinates of the hex's center -function axialToCartesian(q, r) - result = Hex.axialToCartesian(q, r) - return result.x, result.y -end - --- Converts cartesian coordinates to axial hex coordinates --- --- The result is the hex coordinates of the position x, y --- --- @param x, y --- cartesian coordinates --- --- @returns q, r --- hex position -function cartesianToAxial(x, y) - result = Hex.cartesianToAxial(x, y) - return result.x, result.y -end - --- Converts axial hex coordinates to coordinates in the cube based hex model --- --- The result is the cube x,y,z coordinates of the hex q,r --- --- @param q,r --- axial hex coordinates --- --- @returns x, y, z --- cube coordinates -function axialToCube(q, r) - result = Hex.axialToCube(q, r) - return result.x, result.y, result.z -end - --- Converts cube based hex coordinates to axial hex coordinates --- --- The result is the axial hex coordinates of the cube x, y ,z --- --- @param x, y, z --- cube hex coordinates --- --- @returns q, r --- hex coordinates -function cubeToAxial(x, y, z) - result = Hex.cubeToAxial(x, y, z) - return result.x, result.y -end - --- Correctly rounds fractional hex cube coordinates to the correct integer coordinates --- --- @param x, y, z --- fractional cube hex coordinates --- --- @returns rx, ry, rz --- correctly rounded hex cube coordinates -function cubeHexRound(x, y, z) - result = Hex.cubeHexRound(x, y, z) - return result.x, result.y, result.z -end - --- Encodes axial coordinates to a single number --- --- Useful for using hex coordinates as keys in a Lua table --- --- @param q,r --- Axial coordinates. Each must be smaller than OFFSET --- --- @returns s --- A single number encoding q and r. Use decodeAxial() to retrieve q and r from it. -function encodeAxial(q, r) - return Hex.encodeAxial(q, r) -end - - --- Reverses encodeAxial() --- --- @param s --- Encoded hex coordinates, generated with encodeAxial() --- --- @returns q, r --- The hex coordinates encoded in s -function decodeAxial(s) - result = Hex.decodeAxial(s) - return result.x, result.y -end - --- Rotates a hex by 60 degrees about the origin clock-wise. -function rotateAxial(q, r) - result = Hex.rotateAxial(q, r) - return result.x, result.y -end - --- Rotates a hex by (60 * n) degrees about the origin clock-wise. -function rotateAxialNTimes(q0, r0, n) - result = Hex.rotateAxialNTimes(q0, r0, n) - return result.x, result.y -end - --- Rotates a list of hexes by (60 * n) degrees about the origin clock-wise. -function rotateHexListNTimes(hexes, n) - local rotatedList = {} - for _, hex in pairs(hexes) do - table.insert(rotatedList, {["q"]=hex.q, ["r"]=hex.r}) - end - - --rotating each hex by the designated angle - for _, hex in pairs(rotatedList) do - hex.q, hex.r = rotateAxialNTimes(hex.q, hex.r, n) - end - - return rotatedList -end - --- Symmetrizes a hex horizontally about the 0,x axis. -function flipHorizontally(q,r) - result = Hex.flipHorizontally(q, r) - return result.x, result.y -end diff --git a/scripts/microbe_stage/manifest.txt b/scripts/microbe_stage/manifest.txt deleted file mode 100644 index 694c410b9d0..00000000000 --- a/scripts/microbe_stage/manifest.txt +++ /dev/null @@ -1,31 +0,0 @@ -//Tables -compound_table.lua -process_table.lua -organelle_table.lua -bacteria_table.lua -biome_table.lua -configs.lua - -biome.lua -procedural_microbes.lua -microbe_stage_hud.lua -hex.lua -microbe_ai.lua -species_system.lua -microbe_replacement.lua -microbe.lua -microbe_control.lua -bacteria_system.lua -patch_system.lua - -// Organelles -organelle_component.lua -organelle.lua -movement_organelle.lua -storage_organelle.lua -process_organelle.lua -nucleus_organelle.lua -agent_vacuole.lua - -// Setup -setup.lua diff --git a/scripts/microbe_stage/microbe.as b/scripts/microbe_stage/microbe.as new file mode 100644 index 00000000000..8f1015de647 --- /dev/null +++ b/scripts/microbe_stage/microbe.as @@ -0,0 +1,933 @@ +// Was called everytime this object was created +// setupAbsorberForAllCompounds +#include "microbe_operations.as" +#include "hex.as" +#include "microbe_stage_hud.as" +#include "species_system.as" + + +//! Why is this needed? Is it for(the future when we don't want to +//! absorb everything (or does this skip toxins, which aren't in compound registry) +void setupAbsorberForAllCompounds(CompoundAbsorberComponent@ absorber){ + + uint64 compoundCount = SimulationParameters::compoundRegistry().getSize(); + for(uint a = 0; a < compoundCount; ++a){ + + auto compound = SimulationParameters::compoundRegistry().getTypeData(a); + + absorber.setCanAbsorbCompound(a, true); + } +} + +// Quantity of physics time between each loop distributing compounds +// to organelles. TODO: Modify to reflect microbe size. +const uint COMPOUND_PROCESS_DISTRIBUTION_INTERVAL = 100; + +// Amount the microbes maxmimum bandwidth increases with per organelle +// added. This is a temporary replacement for microbe surface area +const float BANDWIDTH_PER_ORGANELLE = 1.0; + +// The of time it takes for the microbe to regenerate an amount of +// bandwidth equal to maxBandwidth +const uint BANDWIDTH_REFILL_DURATION = 800; + +// No idea what this does (if anything), but it isn't used in the +// process system, or when ejecting compounds. +const float STORAGE_EJECTION_THRESHHOLD = 0.8; + +// The amount of time between each loop to maintaining a fill level +// below STORAGE_EJECTION_THRESHHOLD and eject useless compounds +const uint EXCESS_COMPOUND_COLLECTION_INTERVAL = 1000; + +// The amount of hitpoints each organelle provides to a microbe. +const uint MICROBE_HITPOINTS_PER_ORGANELLE = 10; + +// The minimum amount of oxytoxy (or any agent) needed to be able to shoot. +const float MINIMUM_AGENT_EMISSION_AMOUNT = 0.1; + +// A sound effect thing for bumping with other cell i assume? Probably unused. +const float RELATIVE_VELOCITY_TO_BUMP_SOUND = 6.0; + +// I think (emphasis on think) this is unused. +const float INITIAL_EMISSION_RADIUS = 0.5; + +// The speed reduction when a cell is in rngulfing mode. +const uint ENGULFING_MOVEMENT_DIVISION = 3; + +// The speed reduction when a cell is being engulfed. +const uint ENGULFED_MOVEMENT_DIVISION = 4; + +// The amount of ATP per second spent on being on engulfing mode. +const float ENGULFING_ATP_COST_SECOND = 1.5; + +// The minimum HP ratio between a cell and a possible engulfing victim. +const float ENGULF_HP_RATIO_REQ = 1.5 ; + +// Cooldown between agent emissions, in milliseconds. +const uint AGENT_EMISSION_COOLDOWN = 1000; + + +// class Microbe{ + + +// } +// Use "ObjectID microbeEntity" instead + + +//////////////////////////////////////////////////////////////////////////////// +// MicrobeComponent +// +// Holds data common to all microbes. You probably shouldn't use this directly, +// use MicrobeOperations instead. +//////////////////////////////////////////////////////////////////////////////// +class MicrobeComponent : ScriptComponent{ + + //! This detaches all still attached organelles + //! \todo There might be a more graceful way to do this + ~MicrobeComponent(){ + + LOG_INFO("MicrobeComponent destroyed: " + microbeEntity); + + for(uint i = 0; i < organelles.length(); ++i){ + + organelles[i].onDestroyedWithMicrobe(microbeEntity); + } + + organelles.resize(0); + } + + //! This has to be called after creating this + void init(ObjectID forEntity, bool isPlayerMicrobe, const string &in speciesName){ + + this.speciesName = speciesName; + this.isPlayerMicrobe = isPlayerMicrobe; + this.microbeEntity = forEntity; + + // Microbe system update should initialize this component on next tick + } + + // void load(storage){ + + // auto organelles = storage.get("organelles", {}); + // for(i = 1,organelles.size()){ + // auto organelleStorage = organelles.get(i); + // auto organelle = Organelle.loadOrganelle(organelleStorage); + // auto q = organelle.position.q; + // auto r = organelle.position.r; + // auto s = encodeAxial(q, r); + // this.organelles[s] = organelle; + // } + // this.hitpoints = storage.get("hitpoints", 0); + // this.speciesName = storage.get("speciesName", "Default"); + // this.maxHitpoints = storage.get("maxHitpoints", 0); + // this.maxBandwidth = storage.get("maxBandwidth", 0); + // this.remainingBandwidth = storage.get("remainingBandwidth", 0); + // this.isPlayerMicrobe = storage.get("isPlayerMicrobe", false); + // this.speciesName = storage.get("speciesName", ""); + + // // auto compoundPriorities = storage.get("compoundPriorities", {}) + // // for(i = 1,compoundPriorities.size()){ + // // auto compound = compoundPriorities.get(i) + // // this.compoundPriorities[compound.get("compoundId", 0)] = compound.get("priority", 0) + // // } + // } + + + // void storage(storage){ + // // Organelles + // auto organelles = StorageList() + // for(_, organelle in pairs(this.organelles)){ + // auto organelleStorage = organelle.storage(); + // organelles.append(organelleStorage); + // } + // storage.set("organelles", organelles); + // storage.set("hitpoints", this.hitpoints); + // storage.set("speciesName", this.speciesName); + // storage.set("maxHitpoints", this.maxHitpoints); + // storage.set("remainingBandwidth", this.remainingBandwidth); + // storage.set("maxBandwidth", this.maxBandwidth); + // storage.set("isPlayerMicrobe", this.isPlayerMicrobe); + // storage.set("speciesName", this.speciesName); + + // // auto compoundPriorities = StorageList() + // // for(compoundId, priority in pairs(this.compoundPriorities)){ + // // compound = StorageContainer() + // // compound.set("compoundId", compoundId) + // // compound.set("priority", priority) + // // compoundPriorities.append(compound) + // // } + // // storage.set("compoundPriorities", compoundPriorities) + // } + + + string speciesName; + // TODO: initialize + Float4 speciesColour; + + uint hitpoints; + uint maxHitpoints = 0; + bool dead = false; + uint deathTimer = 0; + array organelles; + // Organelles with complete resonsiblity for a specific compound + // (such as agentvacuoles) + // Keys are the CompoundId of the agent and the value is int + // specifying how many there are + dictionary specialStorageOrganelles; + + Float3 movementDirection = Float3(0, 0, 0); + Float3 facingTargetPoint = Float3(0, 0, 0); + float microbetargetdirection = 0; + float movementFactor = 1.0; // Multiplied on the movement speed of the microbe. + double capacity = 0; // The amount that can be stored in the + // microbe. NOTE: This does not include + // special storage organelles. + double stored = 0; // The amount stored in the microbe. NOTE: + // This does not include special storage + // organelles. + bool initialized = false; + bool isPlayerMicrobe = false; + float maxBandwidth = 10.0 * BANDWIDTH_PER_ORGANELLE; // wtf is a bandwidth anyway? + float remainingBandwidth = 0.0; + uint compoundCollectionTimer = EXCESS_COMPOUND_COLLECTION_INTERVAL; + bool isCurrentlyEngulfing = false; + bool isBeingEngulfed = false; + bool wasBeingEngulfed = false; + ObjectID hostileEngulfer = NULL_OBJECT; + uint agentEmissionCooldown = 0; + // Is this the place where the actual flash duration works? + // The one in the organelle class doesn't work + uint flashDuration = 0; + Float4 flashColour = Float4(0, 0, 0, 0); + uint reproductionStage = 0; + + + // New state variables that MicrobeSystem also uses + bool engulfMode = false; + bool in_editor = false; + + // ObjectID microbe; + ObjectID microbeEntity = NULL_OBJECT; +} + +//! Helper for MicrobeSystem +class MicrobeSystemCached{ + + MicrobeSystemCached(ObjectID entity, CompoundAbsorberComponent@ first, + MicrobeComponent@ second, RenderNode@ third, Physics@ fourth, + MembraneComponent@ fifth, CompoundBagComponent@ sixth + ) { + this.entity = entity; + @this.first = first; + @this.second = second; + @this.third = third; + @this.fourth = fourth; + @this.fifth = fifth; + @this.sixth = sixth; + } + + ObjectID entity = -1; + + CompoundAbsorberComponent@ first; + MicrobeComponent@ second; + RenderNode@ third; + Physics@ fourth; + MembraneComponent@ fifth; + CompoundBagComponent@ sixth; + // TODO: determine if this is accessed frequently enough that it should be here + // Physics ; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// MicrobeSystem +// +// Updates microbes +//////////////////////////////////////////////////////////////////////////////// +// TODO: This system is HUUUUUUGE! D: +// We should try to separate it into smaller systems. +// For example, the agents should be handled in another system +// (however we're going to redo agents so we should wait until then for that one) +// This is now also split into MicrobeOperations which implements all the methods that don't +// necessarily need instance data in this class (this is most things) so that they can be +// called from different places. Functions that shouldn't be called from any other place are +// kept here +class MicrobeSystem : ScriptSystem{ + + void Init(GameWorld@ w){ + + @this.world = cast(w); + assert(this.world !is null, "MicrobeSystem expected CellStageWorld"); + } + + void Release(){} + + void Run(){ + // // Note that this triggers every frame there is a collision + // for(_, collision in pairs(this.microbeCollisions.collisions())){ + // auto entity1 = Entity(collision.entityId1, this.gameState.wrapper); + // auto entity2 = Entity(collision.entityId2, this.gameState.wrapper); + // if(entity1.exists() and entity2.exists()){ + // // Engulf initiation + // MicrobeSystem.checkEngulfment(entity1, entity2); + // MicrobeSystem.checkEngulfment(entity2, entity1); + // } + // } + + // this.microbeCollisions.clearCollisions() + + // // TEMP, DELETE FOR 0.3.3!!!!!!!! + // for(_, collision in pairs(this.agentCollisions.collisions())){ + // auto entity = Entity(collision.entityId1, this.gameState.wrapper); + // auto agent = Entity(collision.entityId2, this.gameState.wrapper); + + // if(entity.exists() and agent.exists()){ + // MicrobeSystem.damage(entity, .5, "toxin"); + // agent.destroy(); + // } + // } + + // this.agentCollisions.clearCollisions() + + // for(_, collision in pairs(this.bacteriaCollisions.collisions())){ + // local microbe_entity = Entity(collision.entityId1, this.gameState.wrapper); + // local bacterium_entity = Entity(collision.entityId2, this.gameState.wrapper); + + // if(microbe_entity.exists() and bacterium_entity.exists()){ + // if(world.GetComponent_Bacterium(bacterium_entity) !is null){ + // auto bacterium = Bacterium(bacterium_entity); + // bacterium.damage(4); + // } + // } + // } + // this.bacteriaCollisions.clearCollisions(); + + for(uint i = 0; i < CachedComponents.length(); ++i){ + updateMicrobe(CachedComponents[i], TICKSPEED); + } + } + + void Clear(){ + + CachedComponents.resize(0); + } + + void CreateAndDestroyNodes(){ + + + // Delegate to helper // + ScriptSystemNodeHelper(world, @CachedComponents, SystemComponents); + } + + // TODO: make sure these work fine after converting + // this.microbeCollisions = CollisionFilter( + // "microbe", + // "microbe" + // ) + // // Temporary for 0.3.2, should be moved to separate system. + // this.agentCollisions = CollisionFilter( + // "microbe", + // "agent" + // ) + + // this.bacteriaCollisions = CollisionFilter( + // "microbe", + // "bacteria" + // ) + + // this.microbes = {} + // } + + // Updates the microbe's state + void updateMicrobe(MicrobeSystemCached@ components, uint logicTime){ + auto microbeEntity = components.entity; + + if(microbeEntity == -1){ + + LOG_ERROR("MicrobeSystem: updateMicrobe: invalid microbe entity hasn't " + "set a ObjectID, did someone forget to call 'init'?"); + return; + } + + MicrobeComponent@ microbeComponent = components.second; + MembraneComponent@ membraneComponent = components.fifth; + RenderNode@ sceneNodeComponent = components.third; + CompoundAbsorberComponent@ compoundAbsorberComponent = components.first; + CompoundBagComponent@ compoundBag = components.sixth; + + if(!microbeComponent.initialized){ + + LOG_ERROR("Microbe is not initialized: " + microbeEntity); + return; + } + + if(microbeComponent.dead){ + microbeComponent.deathTimer = microbeComponent.deathTimer - logicTime; + microbeComponent.flashDuration = 0; + if(microbeComponent.deathTimer <= 0){ + if(microbeComponent.isPlayerMicrobe == true){ + MicrobeOperations::respawnPlayer(world); + } else { + + auto physics = world.GetComponent_Physics(microbeEntity); + + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + + // This Collision doesn't really need to be + // updated here, but this keeps us from + // changing onRemovedFromMicrobe to allow + // skipping it + microbeComponent.organelles[i].onRemovedFromMicrobe(microbeEntity, + physics.Collision); + } + + // Safe destroy before next tick + world.QueueDestroyEntity(microbeEntity); + } + } + } else { + // Recalculating agent cooldown time. + microbeComponent.agentEmissionCooldown = max( + microbeComponent.agentEmissionCooldown - logicTime, 0); + + //calculate storage. + calculateStorageSpace(microbeEntity); + + compoundBag.storageSpace = microbeComponent.capacity; + + // StorageOrganelles + updateCompoundAbsorber(microbeEntity); + + // Regenerate bandwidth + regenerateBandwidth(microbeEntity, logicTime); + + // Attempt to absorb queued compounds + auto absorbed = compoundAbsorberComponent.getAbsorbedCompounds(); + for(uint i = 0; i < absorbed.length(); ++i){ + CompoundId compound = absorbed[i]; + auto amount = compoundAbsorberComponent.absorbedCompoundAmount(compound); + if(amount > 0.0){ + MicrobeOperations::storeCompound(world, microbeEntity, compound, + amount, true); + } + } + // Flash membrane if something happens. + if(microbeComponent.flashDuration != 0 && + microbeComponent.flashColour != Float4(0, 0, 0, 0) + ){ + if(microbeComponent.flashDuration >= logicTime){ + + microbeComponent.flashDuration = microbeComponent.flashDuration - + logicTime; + + } else { + // Would wrap over to very large number + microbeComponent.flashDuration = 0; + } + + // How frequent it flashes, would be nice to update + // the flash void to have this variable{ + + if((microbeComponent.flashDuration % 600.0f) < 300){ + membraneComponent.setColour(microbeComponent.flashColour); + } else { + // Restore colour + MicrobeOperations::applyMembraneColour(world, microbeEntity); + } + + if(microbeComponent.flashDuration <= 0){ + microbeComponent.flashDuration = 0; + // Restore colour + MicrobeOperations::applyMembraneColour(world, microbeEntity); + } + } + + microbeComponent.compoundCollectionTimer = + microbeComponent.compoundCollectionTimer + logicTime; + + while(microbeComponent.compoundCollectionTimer > + EXCESS_COMPOUND_COLLECTION_INTERVAL) + { + // For every COMPOUND_DISTRIBUTION_INTERVAL passed + + microbeComponent.compoundCollectionTimer = + microbeComponent.compoundCollectionTimer - + EXCESS_COMPOUND_COLLECTION_INTERVAL; + + MicrobeOperations::purgeCompounds(world, microbeEntity); + + atpDamage(microbeEntity); + } + + // First organelle run: updates all the organelles and heals the broken ones. + if(microbeComponent.hitpoints < microbeComponent.maxHitpoints){ + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + + auto organelle = microbeComponent.organelles[i]; + // Update the organelle. + organelle.update(logicTime); + + // If the organelle is hurt. + if(organelle.getCompoundBin() < 1.0){ + // Give the organelle access to the compound bag to take some compound. + organelle.growOrganelle( + world.GetComponent_CompoundBagComponent(microbeEntity), logicTime); + + // An organelle was damaged and we tried to + // heal it, so our health might be different. + MicrobeOperations::calculateHealthFromOrganelles(world, microbeEntity); + } + } + } else { + auto reproductionStageComplete = true; + array organellesToAdd; + + // Grow all the large organelles. + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + + auto organelle = microbeComponent.organelles[i]; + + // Update the organelle. + organelle.update(logicTime); + + // We are in G1 phase of the cell cycle, duplicate all organelles. + if(organelle.organelle.name != "nucleus" && + microbeComponent.reproductionStage == 0) + { + // If the organelle is not split, give it some + // compounds to make it larger. + if(organelle.getCompoundBin() < 2.0 && !organelle.wasSplit){ + // Give the organelle access to the + // compound bag to take some compound. + organelle.growOrganelle( + world.GetComponent_CompoundBagComponent(microbeEntity), + logicTime); + + reproductionStageComplete = false; + + // if the organelle was split and has a + // bin less 1, it must have been damaged. + } else if(organelle.getCompoundBin() < 1.0 && organelle.wasSplit){ + // Give the organelle access to the + // compound bag to take some compound. + organelle.growOrganelle( + world.GetComponent_CompoundBagComponent(microbeEntity), + logicTime); + + // If the organelle is twice its size... + } else if(organelle.getCompoundBin() >= 2.0){ + + //Queue this organelle for splitting after the loop. + //(To avoid "cutting down the branch we're sitting on"). + organellesToAdd.insertLast(organelle); + } + // In the S phase, the nucleus grows as chromatin is duplicated. + } else if (organelle.organelle.name == "nucleus" && + microbeComponent.reproductionStage == 1) + { + // If the nucleus hasn't finished replicating + // its DNA, give it some compounds. + if(organelle.getCompoundBin() < 2.0){ + // Give the organelle access to the compound + // back to take some compound. + organelle.growOrganelle( + world.GetComponent_CompoundBagComponent(microbeEntity), + logicTime); + reproductionStageComplete = false; + } + } + } + + //Splitting the queued organelles. + for(uint i = 0; i < organellesToAdd.length(); ++i){ + + PlacedOrganelle@ organelle = organellesToAdd[i]; + + LOG_INFO("ready to split " + organelle.organelle.name); + + // Mark this organelle as done and return to its normal size. + organelle.reset(); + organelle.wasSplit = true; + // Create a second organelle. + auto organelle2 = splitOrganelle(microbeEntity, organelle); + organelle2.wasSplit = true; + organelle2.isDuplicate = true; + @organelle2.sisterOrganelle = organelle; + } + + if(organellesToAdd.length() > 0){ + // Redo the cell membrane. + membraneComponent.clear(); + } + + if(reproductionStageComplete && microbeComponent.reproductionStage < 2){ + microbeComponent.reproductionStage += 1; + } + + // To finish the G2 phase we just need more than a threshold of compounds. + if(microbeComponent.reproductionStage == 2 || + microbeComponent.reproductionStage == 3) + { + readyToReproduce(microbeEntity); + } + } + + if(microbeComponent.engulfMode){ + // Drain atp and if(we run out){ disable engulfmode + auto cost = ENGULFING_ATP_COST_SECOND/1000*logicTime; + + if(MicrobeOperations::takeCompound(world, microbeEntity, + SimulationParameters::compoundRegistry().getTypeId("atp"), cost) < + cost - 0.001) + { + LOG_INFO("too little atp, disabling - engulfing"); + MicrobeOperations::toggleEngulfMode(world, microbeEntity); + } + // Flash the membrane blue. + MicrobeOperations::flashMembraneColour(world, microbeEntity, 3000, + Float4(0.2,0.5,1.0,0.5)); + } + + if(microbeComponent.isBeingEngulfed && microbeComponent.wasBeingEngulfed){ + MicrobeOperations::damage(world, microbeEntity, int(logicTime * 0.000025 * + microbeComponent.maxHitpoints), "isBeingEngulfed - Microbe.update()s"); + // Else If we were but are no longer, being engulfed + } else if(microbeComponent.wasBeingEngulfed){ + MicrobeOperations::removeEngulfedEffect(world, microbeEntity); + } + // Used to detect when engulfing stops + microbeComponent.isBeingEngulfed = false; + compoundAbsorberComponent.setAbsorbtionCapacity(min(microbeComponent.capacity - + microbeComponent.stored + 10, microbeComponent.remainingBandwidth)); + } + } + + // ------------------------------------ // + // Microbe operations only done by this class + //! Updates the used storage space in a microbe and stores it in the microbe component + void calculateStorageSpace(ObjectID microbeEntity){ + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + microbeComponent.stored = 0; + uint64 compoundCount = SimulationParameters::compoundRegistry().getSize(); + for(uint a = 0; a < compoundCount; ++a){ + + microbeComponent.stored += MicrobeOperations::getCompoundAmount(world, + microbeEntity, a); + } + } + + + // For updating the compound absorber + // + // Toggles the absorber on and off depending on the remaining storage + // capacity of the storage organelles. + void updateCompoundAbsorber(ObjectID microbeEntity){ + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + auto compoundAbsorberComponent = world.GetComponent_CompoundAbsorberComponent( + microbeEntity); + + if(//microbeComponent.stored >= microbeComponent.capacity or + microbeComponent.remainingBandwidth < 1 || + microbeComponent.dead) + { + compoundAbsorberComponent.disable(); + } else { + compoundAbsorberComponent.enable(); + } + } + + void regenerateBandwidth(ObjectID microbeEntity, int logicTime){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + auto addedBandwidth = microbeComponent.remainingBandwidth + logicTime * + (microbeComponent.maxBandwidth / BANDWIDTH_REFILL_DURATION); + + microbeComponent.remainingBandwidth = min(addedBandwidth, + microbeComponent.maxBandwidth); + } + + // Stuff that should be maybe moved out of here: + // void checkEngulfment(ObjectID engulferMicrobeEntity, ObjectID engulfedMicrobeEntity){ + // auto body = world.GetComponent_RigidBodyComponent(engulferMicrobeEntity, RigidBodyComponent); + // auto microbe1Comp = world.GetComponent_MicrobeComponent(engulferMicrobeEntity, MicrobeComponent); + // auto microbe2Comp = world.GetComponent_MicrobeComponent(engulfedMicrobeEntity, MicrobeComponent); + // auto soundSourceComponent = world.GetComponent_SoundSourceComponent(engulferMicrobeEntity, SoundSourceComponent); + // auto bodyEngulfed = world.GetComponent_RigidBodyComponent(engulfedMicrobeEntity, RigidBodyComponent); + + // // That actually happens sometimes, and i think it shouldn't. :/ + // // Probably related to a collision detection bug. + // // assert(body !is null, "Microbe without a rigidBody tried to engulf.") + // // assert(bodyEngulfed !is null, "Microbe without a rigidBody tried to be engulfed.") + // if(body is null || bodyEngulfed is null) + // return; + + // if(microbe1Comp.engulfMode && microbe1Comp.maxHitpoints > ( + // ENGULF_HP_RATIO_REQ * microbe2Comp.maxHitpoints) && + // microbe1Comp.dead == false && microbe2Comp.dead == false) + // { + // if(!microbe1Comp.isCurrentlyEngulfing){ + // //We have just started engulfing + // microbe2Comp.movementFactor = microbe2Comp.movementFactor / + // ENGULFED_MOVEMENT_DIVISION; + // microbe1Comp.isCurrentlyEngulfing = true; + // microbe2Comp.wasBeingEngulfed = true; + // microbe2Comp.hostileEngulfer = engulferMicrobeEntity; + // body.disableCollisionsWith(engulfedMicrobeEntity.id); + // soundSourceComponent.playSound("microbe-engulfment"); + // } + + // //isBeingEngulfed is set to false every frame + // // we detect engulfment stopped by isBeingEngulfed being + // // false while wasBeingEngulfed is true + // microbe2Comp.isBeingEngulfed = true; + // } + // } + + + PlacedOrganelle@ splitOrganelle(ObjectID microbeEntity, PlacedOrganelle@ organelle){ + auto q = organelle.q; + auto r = organelle.r; + + //Spiral search for space for the organelle + int radius = 1; + while(true){ + //Moves into the ring of radius "radius" and center the old organelle + Int2 radiusOffset = Int2(HEX_NEIGHBOUR_OFFSET[ + formatInt(int(HEX_SIDE::BOTTOM_LEFT))]); + q = q + radiusOffset.X; + r = r + radiusOffset.Y; + + //Iterates in the ring + for(int side = 1; side <= 6; ++side){ + Int2 offset = Int2(HEX_NEIGHBOUR_OFFSET[formatInt(side)]); + //Moves "radius" times into each direction + for(int i = 1; i <= radius; ++i){ + q = q + offset.X; + r = r + offset.Y; + + //Checks every possible rotation value. + for(int j = 0; j <= 5; ++j){ + + // auto rotation = 360 * j / 6; + + // In the lua code the rotation is i * 60 here + // and not in fact the rotation variable + + // Why doesn't this take a rotation parameter? + // Does it incorrectly assume that the Organelle type has a rotated + // hex list? + if(MicrobeOperations::validPlacement(world, microbeEntity, + organelle.organelle, {q, r})) + { + auto newOrganelle = PlacedOrganelle(organelle, q, r, i*60); + + LOG_INFO("placed " + organelle.organelle.name + " at " + + q + ", " + r); + MicrobeOperations::addOrganelle(world, microbeEntity, + newOrganelle); + return newOrganelle; + } + } + } + } + + radius = radius + 1; + } + + return null; + } + + + // Damage the microbe if its too low on ATP. + void atpDamage(ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + if(MicrobeOperations::getCompoundAmount(world, microbeEntity, + SimulationParameters::compoundRegistry().getTypeId("atp")) < 1.0) + { + // TODO: put this on a GUI notification. + // if(microbeComponent.isPlayerMicrobe and not this.playerAlreadyShownAtpDamage){ + // this.playerAlreadyShownAtpDamage = true + // showMessage("No ATP hurts you!") + // } + MicrobeOperations::damage(world, microbeEntity, + int(EXCESS_COMPOUND_COLLECTION_INTERVAL * + 0.000002 * microbeComponent.maxHitpoints), "atpDamage"); + // Microbe takes 2% of max hp per second in damage + } + } + + // // Drains an agent from the microbes special storage and emits it + // // + // // @param compoundId + // // The compound id of the agent to emit + // // + // // @param maxAmount + // // The maximum amount to try to emit + // void emitAgent(ObjectID microbeEntity, CompoundId compoundId, double maxAmount){ + // auto microbeComponent = world.GetComponent_MicrobeComponent(microbeEntity, MicrobeComponent); + // auto sceneNodeComponent = world.GetComponent_OgreSceneNodeComponent(microbeEntity, OgreSceneNodeComponent); + // auto soundSourceComponent = world.GetComponent_SoundSourceComponent(microbeEntity, SoundSourceComponent); + // auto membraneComponent = world.GetComponent_MembraneComponent(microbeEntity, MembraneComponent); + + // // Cooldown code + // if(microbeComponent.agentEmissionCooldown > 0){ return; } + // auto numberOfAgentVacuoles = microbeComponent.specialStorageOrganelles[compoundId]; + + // // Only shoot if you have agent vacuoles. + // if(numberOfAgentVacuoles == 0 or numberOfAgentVacuoles == 0){ return; } + + // // The cooldown time is inversely proportional to the amount of agent vacuoles. + // microbeComponent.agentEmissionCooldown = AGENT_EMISSION_COOLDOWN / + // numberOfAgentVacuoles; + + // if(MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) > + // MINIMUM_AGENT_EMISSION_AMOUNT) + // { + // soundSourceComponent.playSound("microbe-release-toxin"); + + // // Calculate the emission angle of the agent emitter + // local organelleX, organelleY = axialToCartesian(0, -1); // The front of the microbe + // auto membraneCoords = membraneComponent.getExternOrganellePos( + // organelleX, organelleY); + + // auto angle = math.atan2(organelleY, organelleX); + // if(angle < 0){ + // angle = angle + 2*math.pi; + // } + // angle = -(angle * 180/math.pi -90 ) % 360; + + // // Find the direction the microbe is facing + // auto yAxis = sceneNodeComponent.transform.orientation.yAxis(); + // auto microbeAngle = math.atan2(yAxis.x, yAxis.y); + // if(microbeAngle < 0){ + // microbeAngle = microbeAngle + 2*math.pi; + // } + // microbeAngle = microbeAngle * 180/math.pi; + // // Take the microbe angle into account so we get world relative degrees + // auto finalAngle = (angle + microbeAngle) % 360; + + // auto s = math.sin(finalAngle/180*math.pi); + // auto c = math.cos(finalAngle/180*math.pi); + + // auto xnew = -membraneCoords[1] * c + membraneCoords[2] * s; + // auto ynew = membraneCoords[1] * s + membraneCoords[2] * c; + + // auto direction = Vector3(xnew, ynew, 0); + // direction.normalise(); + // auto amountToEject = MicrobeSystem.takeCompound(microbeEntity, + // compoundId, maxAmount/10.0); + // createAgentCloud(compoundId, sceneNodeComponent.transform.position.x + xnew, + // sceneNodeComponent.transform.position.y + ynew, direction, + // amountToEject * 10); + // } + // } + + // void transferCompounds(ObjectID fromEntity, ObjectID toEntity){ + // for(_, compoundID in pairs(SimulationParameters::compoundRegistry().getCompoundList())){ + // auto amount = MicrobeSystem.getCompoundAmount(fromEntity, compoundID); + + // if(amount != 0){ + // // Is it possible that compounds are created or destroyed here as + // // the actual amounts aren't checked (that these functions should return) + // MicrobeSystem.takeCompound(fromEntity, compoundID, amount, false); + // MicrobeSystem.storeCompound(toEntity, compoundID, amount, false); + // } + // } + // } + + void divide(ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + // auto soundSourceComponent = world.GetComponent_SoundSourceComponent(microbeEntity); + auto membraneComponent = world.GetComponent_MembraneComponent(microbeEntity); + auto position = world.GetComponent_Position(microbeEntity); + auto rigidBodyComponent = world.GetComponent_Physics(microbeEntity); + + // Create the one daughter cell. + // The empty string here is the name of the new cell, which could be more descriptive + // to set to something based on the original cell + auto copyEntity = MicrobeOperations::_createMicrobeEntity(world, "", true, + microbeComponent.speciesName, false); + MicrobeComponent@ microbeComponentCopy = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(copyEntity)); + auto rigidBodyComponentCopy = world.GetComponent_Physics(copyEntity); + auto positionCopy = world.GetComponent_Position(copyEntity); + + //Separate the two cells. + positionCopy._Position = Float3(position._Position.X - + membraneComponent.getCellDimensions() / 2, + 0, position._Position.Z); + rigidBodyComponentCopy.JumpTo(positionCopy); + + position._Position = Float3(position._Position.X + + membraneComponent.getCellDimensions() / 2, + 0, position._Position.Z); + rigidBodyComponent.JumpTo(position); + + + // Split the compounds evenly between the two cells. + for(uint64 compoundID = 0; compoundID < + SimulationParameters::compoundRegistry().getSize(); ++compoundID) + { + auto amount = MicrobeOperations::getCompoundAmount(world, microbeEntity, + compoundID); + + if(amount != 0){ + MicrobeOperations::takeCompound(world, microbeEntity, compoundID, + amount / 2/*, false*/ ); + // Not sure what the false here means, it wasn't a + // parameter in the original lua function so it did + // nothing even then? + MicrobeOperations::storeCompound(world, copyEntity, compoundID, + amount / 2, false); + } + } + + microbeComponent.reproductionStage = 0; + microbeComponentCopy.reproductionStage = 0; + + world.Create_SpawnedComponent(copyEntity, MICROBE_SPAWN_RADIUS); + + //play the split sound + GetEngine().GetSoundDevice().Play2DSoundEffect("Data/Sound/soundeffects/reproduction.ogg"); + } + + // Copies this microbe. The new microbe will not have the stored compounds of this one. + void readyToReproduce(ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + if(microbeComponent.isPlayerMicrobe){ + showReproductionDialog(world); + microbeComponent.reproductionStage = 0; + } else { + // Return the first cell to its normal, non duplicated cell arangement. + Species::applyTemplate(world, microbeEntity, + MicrobeOperations::getSpeciesComponent(world, microbeEntity)); + + divide(microbeEntity); + } + } + + private array CachedComponents; + private CellStageWorld@ world; + + private array SystemComponents = { + ScriptSystemUses(CompoundAbsorberComponent::TYPE), + ScriptSystemUses("MicrobeComponent"), + ScriptSystemUses(RenderNode::TYPE), + ScriptSystemUses(Physics::TYPE), + ScriptSystemUses(MembraneComponent::TYPE), + ScriptSystemUses(CompoundBagComponent::TYPE) + }; +} diff --git a/scripts/microbe_stage/microbe.lua b/scripts/microbe_stage/microbe.lua deleted file mode 100644 index 5e588227289..00000000000 --- a/scripts/microbe_stage/microbe.lua +++ /dev/null @@ -1,1328 +0,0 @@ --------------------------------------------------------------------------------- --- MicrobeComponent --- --- Holds data common to all microbes. You probably shouldn't use this directly, --- use the Microbe class (below) instead. --------------------------------------------------------------------------------- -MicrobeComponent = class( - function(self, isPlayerMicrobe, speciesName) - self.speciesName = speciesName - self.hitpoints = 0 - self.maxHitpoints = 0 - self.dead = false - self.deathTimer = 0 - self.organelles = {} - self.processOrganelles = {} -- Organelles responsible for producing compounds from other compounds - self.specialStorageOrganelles = {} -- Organelles with complete resonsiblity for a specific compound (such as agentvacuoles) - self.movementDirection = Vector3(0, 0, 0) - self.facingTargetPoint = Vector3(0, 0, 0) - self.microbetargetdirection = 0 - self.movementFactor = 1.0 -- Multiplied on the movement speed of the microbe. - self.capacity = 0 -- The amount that can be stored in the microbe. NOTE: This does not include special storage organelles - self.stored = 0 -- The amount stored in the microbe. NOTE: This does not include special storage organelles - self.initialized = false - self.isPlayerMicrobe = isPlayerMicrobe - self.maxBandwidth = 10.0 * BANDWIDTH_PER_ORGANELLE -- wtf is a bandwidth anyway? - self.remainingBandwidth = 0 - self.compoundCollectionTimer = EXCESS_COMPOUND_COLLECTION_INTERVAL - self.isCurrentlyEngulfing = false - self.isBeingEngulfed = false - self.wasBeingEngulfed = false - self.hostileEngulfer = nil - self.agentEmissionCooldown = 0 - self.flashDuration = nil - self.flashColour = nil - self.reproductionStage = 0 -- 1 for G1 complete, 2 for S complete, 3 for G2 complete, and 4 for reproduction finished. - end -) - -MicrobeComponent.TYPE_NAME = "MicrobeComponent" - -COMPOUND_PROCESS_DISTRIBUTION_INTERVAL = 100 -- quantity of physics time between each loop distributing compounds to organelles. TODO: Modify to reflect microbe size. -BANDWIDTH_PER_ORGANELLE = 1.0 -- amount the microbes maxmimum bandwidth increases with per organelle added. This is a temporary replacement for microbe surface area -BANDWIDTH_REFILL_DURATION = 800 -- The of time it takes for the microbe to regenerate an amount of bandwidth equal to maxBandwidth -STORAGE_EJECTION_THRESHHOLD = 0.8 -EXCESS_COMPOUND_COLLECTION_INTERVAL = 1000 -- The amount of time between each loop to maintaining a fill level below STORAGE_EJECTION_THRESHHOLD and eject useless compounds -MICROBE_HITPOINTS_PER_ORGANELLE = 10 -MINIMUM_AGENT_EMISSION_AMOUNT = .1 -REPRODUCTASE_TO_SPLIT = 5 -RELATIVE_VELOCITY_TO_BUMP_SOUND = 6 -INITIAL_EMISSION_RADIUS = 0.5 -ENGULFING_MOVEMENT_DIVISION = 3 -ENGULFED_MOVEMENT_DIVISION = 4 -ENGULFING_ATP_COST_SECOND = 1.5 -ENGULF_HP_RATIO_REQ = 1.5 -AGENT_EMISSION_COOLDOWN = 1000 -- Cooldown between agent emissions, in milliseconds. - -function MicrobeComponent:load(storage) - - local organelles = storage:get("organelles", {}) - for i = 1,organelles:size() do - local organelleStorage = organelles:get(i) - local organelle = Organelle.loadOrganelle(organelleStorage) - local q = organelle.position.q - local r = organelle.position.r - local s = encodeAxial(q, r) - self.organelles[s] = organelle - end - self.hitpoints = storage:get("hitpoints", 0) - self.speciesName = storage:get("speciesName", "Default") - self.maxHitpoints = storage:get("maxHitpoints", 0) - self.maxBandwidth = storage:get("maxBandwidth", 0) - self.remainingBandwidth = storage:get("remainingBandwidth", 0) - self.isPlayerMicrobe = storage:get("isPlayerMicrobe", false) - self.speciesName = storage:get("speciesName", "") - - -- local compoundPriorities = storage:get("compoundPriorities", {}) - -- for i = 1,compoundPriorities:size() do - -- local compound = compoundPriorities:get(i) - -- self.compoundPriorities[compound:get("compoundId", 0)] = compound:get("priority", 0) - -- end -end - - -function MicrobeComponent:storage(storage) - -- Organelles - local organelles = StorageList.new() - for _, organelle in pairs(self.organelles) do - local organelleStorage = organelle:storage() - organelles:append(organelleStorage) - end - storage:set("organelles", organelles) - storage:set("hitpoints", self.hitpoints) - storage:set("speciesName", self.speciesName) - storage:set("maxHitpoints", self.maxHitpoints) - storage:set("remainingBandwidth", self.remainingBandwidth) - storage:set("maxBandwidth", self.maxBandwidth) - storage:set("isPlayerMicrobe", self.isPlayerMicrobe) - storage:set("speciesName", self.speciesName) - - -- local compoundPriorities = StorageList() - -- for compoundId, priority in pairs(self.compoundPriorities) do - -- compound = StorageContainer() - -- compound:set("compoundId", compoundId) - -- compound:set("priority", priority) - -- compoundPriorities:append(compound) - -- end - -- storage:set("compoundPriorities", compoundPriorities) -end - -REGISTER_COMPONENT("MicrobeComponent", MicrobeComponent) - --------------------------------------------------------------------------------- --- MicrobeSystem --- --- Updates microbes --------------------------------------------------------------------------------- --- TODO: This system is HUUUUUUGE! D: --- We should try to separate it into smaller systems. --- For example, the agents should be handled in another system --- (however we're going to redo agents so we should wait until then for that one) -MicrobeSystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - - self.entities = EntityFilter.new( - { - CompoundAbsorberComponent, - MicrobeComponent, - OgreSceneNodeComponent, - RigidBodyComponent, - CollisionComponent - }, - true - ) - self.microbeCollisions = CollisionFilter.new( - "microbe", - "microbe" - ) - -- Temporary for 0.3.2, should be moved to separate system. - self.agentCollisions = CollisionFilter.new( - "microbe", - "agent" - ) - - self.bacteriaCollisions = CollisionFilter.new( - "microbe", - "bacteria" - ) - - self.microbes = {} - end -) - --- I don't feel like checking for each component separately, so let's make a --- loop do it with an assert for good measure (see Microbe.create) -MICROBE_COMPONENTS = { - compoundAbsorber = CompoundAbsorberComponent, - microbe = MicrobeComponent, - rigidBody = RigidBodyComponent, - sceneNode = OgreSceneNodeComponent, - collisionHandler = CollisionComponent, - soundSource = SoundSourceComponent, - membraneComponent = MembraneComponent, - compoundBag = CompoundBagComponent -} - -function MicrobeSystem:init(gameState) - LuaSystem.init(self, "MicrobeSystem", gameState) - self.entities:init(gameState.wrapper) - self.microbeCollisions:init(gameState.wrapper) - self.agentCollisions:init(gameState.wrapper) - self.bacteriaCollisions:init(gameState.wrapper) -end - -function MicrobeSystem:shutdown() - LuaSystem.shutdown(self) - self.entities:shutdown() - self.microbeCollisions:shutdown() - self.agentCollisions:shutdown() - self.bacteriaCollisions:shutdown() -end - -function MicrobeSystem:update(renderTime, logicTime) - for _, entityId in pairs(self.entities:removedEntities()) do - self.microbes[entityId] = nil - end - for _, entityId in pairs(self.entities:addedEntities()) do - local microbeEntity = Entity.new(entityId, self.gameState.wrapper) - self.microbes[entityId] = microbeEntity - end - self.entities:clearChanges() - for _, microbeEntity in pairs(self.microbes) do - MicrobeSystem.updateMicrobe(microbeEntity, logicTime) - end - -- Note that this triggers every frame there is a collision - for _, collision in pairs(self.microbeCollisions:collisions()) do - local entity1 = Entity.new(collision.entityId1, self.gameState.wrapper) - local entity2 = Entity.new(collision.entityId2, self.gameState.wrapper) - if entity1:exists() and entity2:exists() then - -- Engulf initiation - MicrobeSystem.checkEngulfment(entity1, entity2) - MicrobeSystem.checkEngulfment(entity2, entity1) - end - end - self.microbeCollisions:clearCollisions() - - -- TEMP, DELETE FOR 0.3.3!!!!!!!! - for _, collision in pairs(self.agentCollisions:collisions()) do - local entity = Entity.new(collision.entityId1, self.gameState.wrapper) - local agent = Entity.new(collision.entityId2, self.gameState.wrapper) - - if entity:exists() and agent:exists() then - MicrobeSystem.damage(entity, .5, "toxin") - agent:destroy() - end - end - self.agentCollisions:clearCollisions() - - for _, collision in pairs(self.bacteriaCollisions:collisions()) do - local microbe_entity = Entity.new(collision.entityId1, self.gameState.wrapper) - local bacterium_entity = Entity.new(collision.entityId2, self.gameState.wrapper) - - if microbe_entity:exists() and bacterium_entity:exists() then - if not (getComponent(bacterium_entity, Bacterium.COMPONENTS.bacterium) == nil) then - local bacterium = Bacterium(bacterium_entity) - bacterium:damage(4) - end - end - end - self.bacteriaCollisions:clearCollisions() -end - -function MicrobeSystem.checkEngulfment(engulferMicrobeEntity, engulfedMicrobeEntity) - local body = getComponent(engulferMicrobeEntity, RigidBodyComponent) - local microbe1Comp = getComponent(engulferMicrobeEntity, MicrobeComponent) - local microbe2Comp = getComponent(engulfedMicrobeEntity, MicrobeComponent) - local soundSourceComponent = getComponent(engulferMicrobeEntity, SoundSourceComponent) - local bodyEngulfed = getComponent(engulfedMicrobeEntity, RigidBodyComponent) - - -- That actually happens sometimes, and i think it shouldn't. :/ - -- Probably related to a collision detection bug. - -- assert(body ~= nil, "Microbe without a rigidBody tried to engulf.") - -- assert(bodyEngulfed ~= nil, "Microbe without a rigidBody tried to be engulfed.") - if body == nil or bodyEngulfed == nil then return end - - if microbe1Comp.engulfMode and - microbe1Comp.maxHitpoints > ENGULF_HP_RATIO_REQ * microbe2Comp.maxHitpoints and - microbe1Comp.dead == false and microbe2Comp.dead == false then - - if not microbe1Comp.isCurrentlyEngulfing then - --We have just started engulfing - microbe2Comp.movementFactor = microbe2Comp.movementFactor / ENGULFED_MOVEMENT_DIVISION - microbe1Comp.isCurrentlyEngulfing = true - microbe2Comp.wasBeingEngulfed = true - microbe2Comp.hostileEngulfer = engulferMicrobeEntity - body:disableCollisionsWith(engulfedMicrobeEntity.id) - soundSourceComponent:playSound("microbe-engulfment") - end - - --isBeingEngulfed is set to false every frame - -- we detect engulfment stopped by isBeingEngulfed being false while wasBeingEngulfed is true - microbe2Comp.isBeingEngulfed = true - end -end - --- Attempts to obtain an amount of bandwidth for immediate use. --- This should be in conjunction with most operations ejecting or absorbing compounds and agents for microbe. --- --- @param maicrobeEntity --- The entity of the microbe to get the bandwidth from. --- --- @param maxAmount --- The max amount of units that is requested. --- --- @param compoundId --- The compound being requested for volume considerations. --- --- @return --- amount in units avaliable for use. -function MicrobeSystem.getBandwidth(microbeEntity, maxAmount, compoundId) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local compoundVolume = CompoundRegistry.getCompoundUnitVolume(compoundId) - local amount = math.min(maxAmount * compoundVolume, microbeComponent.remainingBandwidth) - microbeComponent.remainingBandwidth = microbeComponent.remainingBandwidth - amount - return amount / compoundVolume -end - -function MicrobeSystem.regenerateBandwidth(microbeEntity, logicTime) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local addedBandwidth = microbeComponent.remainingBandwidth + logicTime * (microbeComponent.maxBandwidth / BANDWIDTH_REFILL_DURATION) - microbeComponent.remainingBandwidth = math.min(addedBandwidth, microbeComponent.maxBandwidth) -end - -function MicrobeSystem.calculateHealthFromOrganelles(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - microbeComponent.hitpoints = 0 - microbeComponent.maxHitpoints = 0 - for _, organelle in pairs(microbeComponent.organelles) do - microbeComponent.hitpoints = microbeComponent.hitpoints + (organelle:getCompoundBin() < 1.0 and organelle:getCompoundBin() or 1.0) * MICROBE_HITPOINTS_PER_ORGANELLE - microbeComponent.maxHitpoints = microbeComponent.maxHitpoints + MICROBE_HITPOINTS_PER_ORGANELLE - end -end - --- Queries the currently stored amount of an compound --- --- @param compoundId --- The id of the compound to query --- --- @returns amount --- The amount stored in the microbe's storage oraganelles -function MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) - return getComponent(microbeEntity, CompoundBagComponent):getCompoundAmount(compoundId) -end - --- Getter for microbe species --- --- returns the species component or nil if it doesn't have a valid species -function MicrobeSystem.getSpeciesComponent(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - return getComponent(microbeComponent.speciesName, g_luaEngine.currentGameState, SpeciesComponent) -end - --- Sets the color of the microbe's membrane. -function MicrobeSystem.setMembraneColour(microbeEntity, colour) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - membraneComponent:setColour(colour.x, colour.y, colour.z, 1) -end - -function MicrobeSystem.flashMembraneColour(microbeEntity, duration, colour) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - if microbeComponent.flashDuration == nil then - microbeComponent.flashColour = colour - microbeComponent.flashDuration = duration - end -end - --- Stores an compound in the microbe's storage organelles --- --- @param compoundId --- The compound to store --- --- @param amount --- The amount to store --- --- @param bandwidthLimited --- Determines if the storage operation is to be limited by the bandwidth of the microbe --- --- @returns leftover --- The amount of compound not stored, due to bandwidth or being full -function MicrobeSystem.storeCompound(microbeEntity, compoundId, amount, bandwidthLimited) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local storedAmount = amount + 0 -- Why are we adding 0? Is this a type-casting thing? - - if bandwidthLimited then - storedAmount = MicrobeSystem.getBandwidth(microbeEntity, amount, compoundId) - end - - storedAmount = math.min(storedAmount , microbeComponent.capacity - microbeComponent.stored) - getComponent(microbeEntity, CompoundBagComponent):giveCompound(tonumber(compoundId), storedAmount) - - microbeComponent.stored = microbeComponent.stored + storedAmount - return amount - storedAmount -end - --- Removes compounds from the microbe's storage organelles --- --- @param compoundId --- The compound to remove --- --- @param maxAmount --- The maximum amount to take --- --- @returns amount --- The amount that was actually taken, between 0.0 and maxAmount. -function MicrobeSystem.takeCompound(microbeEntity, compoundId, maxAmount) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local takenAmount = getComponent(microbeEntity, CompoundBagComponent - ):takeCompound(compoundId, maxAmount) - - microbeComponent.stored = microbeComponent.stored - takenAmount - return takenAmount -end - --- Ejects compounds from the microbes behind position, into the enviroment --- Note that the compounds ejected are created in this function and not taken from the microbe --- --- @param compoundId --- The compound type to create and eject --- --- @param amount --- The amount to eject -function MicrobeSystem.ejectCompound(microbeEntity, compoundId, amount) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - local sceneNodeComponent = getComponent(microbeEntity, OgreSceneNodeComponent) - - -- The back of the microbe - local exitX, exitY = axialToCartesian(0, 1) - local membraneCoords = membraneComponent:getExternOrganellePos(exitX, exitY) - - --Get the distance to eject the compunds - local maxR = 0 - for _, organelle in pairs(microbeComponent.organelles) do - for _, hex in pairs(organelle._hexes) do - if hex.r + organelle.position.r > maxR then - maxR = hex.r + organelle.position.r - end - end - end - - --The distance is two hexes away from the back of the microbe. - --This distance could be precalculated when adding/removing an organelle - --for more efficient pooping. - local ejectionDistance = (maxR + 3) * HEX_SIZE - - local angle = 180 - -- Find the direction the microbe is facing - local yAxis = sceneNodeComponent.transform.orientation:yAxis() - local microbeAngle = math.atan2(yAxis.x, yAxis.y) - if (microbeAngle < 0) then - microbeAngle = microbeAngle + 2 * math.pi - end - microbeAngle = microbeAngle * 180 / math.pi - -- Take the microbe angle into account so we get world relative degrees - local finalAngle = (angle + microbeAngle) % 360 - - local s = math.sin(finalAngle/180*math.pi); - local c = math.cos(finalAngle/180*math.pi); - - local xnew = -membraneCoords[1] * c + membraneCoords[2] * s; - local ynew = membraneCoords[1] * s + membraneCoords[2] * c; - - local amountToEject = MicrobeSystem.takeCompound(microbeEntity, compoundId, amount/10.0) - createCompoundCloud(CompoundRegistry.getCompoundInternalName(compoundId), - sceneNodeComponent.transform.position.x + xnew * ejectionDistance, - sceneNodeComponent.transform.position.y + ynew * ejectionDistance, - amount * 5000) -end - -function MicrobeSystem.respawnPlayer() - local playerEntity = Entity.new("player", g_luaEngine.currentGameState.wrapper) - local microbeComponent = getComponent(playerEntity, MicrobeComponent) - local rigidBodyComponent = getComponent(playerEntity, RigidBodyComponent) - local sceneNodeComponent = getComponent(playerEntity, OgreSceneNodeComponent) - - microbeComponent.dead = false - microbeComponent.deathTimer = 0 - - -- Reset the growth bins of the organelles to full health. - for _, organelle in pairs(microbeComponent.organelles) do - organelle:reset() - end - MicrobeSystem.calculateHealthFromOrganelles(playerEntity) - - rigidBodyComponent:setDynamicProperties( - Vector3(0,0,0), -- Position - Quaternion.new(Radian.new(Degree(0)), Vector3(1, 0, 0)), -- Orientation - Vector3(0, 0, 0), -- Linear velocity - Vector3(0, 0, 0) -- Angular velocity - ) - - sceneNodeComponent.visible = true - sceneNodeComponent.transform.position = Vector3(0, 0, 0) - sceneNodeComponent.transform:touch() - - -- TODO: give the microbe the values from some table instead. - MicrobeSystem.storeCompound(playerEntity, CompoundRegistry.getCompoundId("atp"), 50, false) - - setRandomBiome(g_luaEngine.currentGameState) - global_activeMicrobeStageHudSystem:suicideButtonreset() -end - --- Retrieves the organelle occupying a hex cell --- --- @param q, r --- Axial coordinates, relative to the microbe's center --- --- @returns organelle --- The organelle at (q,r) or nil if the hex is unoccupied -function MicrobeSystem.getOrganelleAt(microbeEntity, q, r) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - - for _, organelle in pairs(microbeComponent.organelles) do - local localQ = q - organelle.position.q - local localR = r - organelle.position.r - if organelle:getHex(localQ, localR) ~= nil then - return organelle - end - end - return nil -end - --- Removes the organelle at a hex cell --- Note that this renders the organelle unusable as we destroy its underlying entity --- --- @param q, r --- Axial coordinates of the organelle's center --- --- @returns success --- True if an organelle has been removed, false if there was no organelle --- at (q,r) -function MicrobeSystem.removeOrganelle(microbeEntity, q, r) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - - local organelle = MicrobeSystem.getOrganelleAt(microbeEntity, q, r) - if not organelle then - return false - end - - local s = encodeAxial(organelle.position.q, organelle.position.r) - microbeComponent.organelles[s] = nil - - rigidBodyComponent.properties.mass = rigidBodyComponent.properties.mass - organelle.mass - rigidBodyComponent.properties:touch() - -- TODO: cache for performance - local compoundShape = CompoundShape.castFrom(rigidBodyComponent.properties.shape) - compoundShape:removeChildShape( - organelle.collisionShape - ) - - organelle:onRemovedFromMicrobe() - - MicrobeSystem.calculateHealthFromOrganelles(microbeEntity) - microbeComponent.maxBandwidth = microbeComponent.maxBandwidth - BANDWIDTH_PER_ORGANELLE -- Temporary solution for decreasing max bandwidth - microbeComponent.remainingBandwidth = microbeComponent.maxBandwidth - - return true -end - -function MicrobeSystem.purgeCompounds(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local compoundBag = getComponent(microbeEntity, CompoundBagComponent) - - local compoundAmountToDump = microbeComponent.stored - microbeComponent.capacity - - -- Uncomment to print compound economic information to the console. - --[[ - if microbeComponent.isPlayerMicrobe then - for compound, _ in pairs(compoundTable) do - compoundId = CompoundRegistry.getCompoundId(compound) - print(compound, compoundBag:getPrice(compoundId), compoundBag:getDemand(compoundId)) - end - end - print("") - ]] - - -- Dumping all the useless compounds (with price = 0). - for _, compoundId in pairs(CompoundRegistry.getCompoundList()) do - local price = compoundBag:getPrice(compoundId) - if price <= 0 then - local amountToEject = MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) - if amount > 0 then amountToEject = MicrobeSystem.takeCompound(microbeEntity, compoundId, amountToEject) end - if amount > 0 then MicrobeSystem.ejectCompound(microbeEntity, compoundId, amountToEject) end - end - end - - if compoundAmountToDump > 0 then - --Calculating each compound price to dump proportionally. - local compoundPrices = {} - local priceSum = 0 - for _, compoundId in pairs(CompoundRegistry.getCompoundList()) do - local amount = MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) - - if amount > 0 then - local price = compoundBag:getPrice(compoundId) - compoundPrices[compoundId] = price - priceSum = priceSum + amount / price - end - end - - --Dumping each compound according to it's price. - for compoundId, price in pairs(compoundPrices) do - local amountToEject = compoundAmountToDump * (MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) / price) / priceSum - if amount > 0 then amountToEject = MicrobeSystem.takeCompound(microbeEntity, compoundId, amountToEject) end - if amount > 0 then MicrobeSystem.ejectCompound(microbeEntity, compoundId, amountToEject) end - end - end -end - -function MicrobeSystem.removeEngulfedEffect(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - - microbeComponent.movementFactor = microbeComponent.movementFactor * ENGULFED_MOVEMENT_DIVISION - microbeComponent.wasBeingEngulfed = false - - local hostileMicrobeComponent = getComponent(microbeComponent.hostileEngulfer, MicrobeComponent) - if hostileMicrobeComponent ~= nil then - hostileMicrobeComponent.isCurrentlyEngulfing = false - end - - local hostileRigidBodyComponent = getComponent(microbeComponent.hostileEngulfer, RigidBodyComponent) - - -- The component is nil sometimes, probably due to despawning. - if hostileRigidBodyComponent ~= nil then - hostileRigidBodyComponent:reenableAllCollisions() - end - -- Causes crash because sound was already stopped. - --microbeComponent.hostileEngulfer.soundSource:stopSound("microbe-engulfment") -end - --- Adds a new organelle --- --- The space at (q,r) must not be occupied by another organelle already. --- --- @param q,r --- Offset of the organelle's center relative to the microbe's center in --- axial coordinates. --- --- @param organelle --- The organelle to add --- --- @return --- returns whether the organelle was added -function MicrobeSystem.addOrganelle(microbeEntity, q, r, rotation, organelle) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - - local s = encodeAxial(q, r) - if microbeComponent.organelles[s] then - return false - end - microbeComponent.organelles[s] = organelle - local x, y = axialToCartesian(q, r) - local translation = Vector3(x, y, 0) - -- Collision shape - -- TODO: cache for performance - local compoundShape = CompoundShape.castFrom(rigidBodyComponent.properties.shape) - compoundShape:addChildShape( - translation, - Quaternion.new(Radian(0), Vector3(1,0,0)), - organelle.collisionShape - ) - rigidBodyComponent.properties.mass = rigidBodyComponent.properties.mass + organelle.mass - rigidBodyComponent.properties:touch() - - organelle:onAddedToMicrobe(microbeEntity, q, r, rotation) - - MicrobeSystem.calculateHealthFromOrganelles(microbeEntity) - microbeComponent.maxBandwidth = microbeComponent.maxBandwidth + BANDWIDTH_PER_ORGANELLE -- Temporary solution for increasing max bandwidth - microbeComponent.remainingBandwidth = microbeComponent.maxBandwidth - - -- Send the organelles to the membraneComponent so that the membrane can "grow" - local localQ = q - organelle.position.q - local localR = r - organelle.position.r - if organelle:getHex(localQ, localR) ~= nil then - for _, hex in pairs(organelle._hexes) do - local q = hex.q + organelle.position.q - local r = hex.r + organelle.position.r - local x, y = axialToCartesian(q, r) - membraneComponent:sendOrganelles(x, y) - end - return organelle - end - - return true -end - --- TODO: we have a similar method in procedural_microbes.lua and another one in microbe_editor.lua. --- They probably should all use the same one. -function MicrobeSystem.validPlacement(microbeEntity, organelle, q, r) - local touching = false; - for s, hex in pairs(organelle._hexes) do - - local organelle = MicrobeSystem.getOrganelleAt(microbeEntity, hex.q + q, hex.r + r) - if organelle then - if organelle.name ~= "cytoplasm" then - return false - end - end - - if MicrobeSystem.getOrganelleAt(microbeEntity, hex.q + q + 0, hex.r + r - 1) or - MicrobeSystem.getOrganelleAt(microbeEntity, hex.q + q + 1, hex.r + r - 1) or - MicrobeSystem.getOrganelleAt(microbeEntity, hex.q + q + 1, hex.r + r + 0) or - MicrobeSystem.getOrganelleAt(microbeEntity, hex.q + q + 0, hex.r + r + 1) or - MicrobeSystem.getOrganelleAt(microbeEntity, hex.q + q - 1, hex.r + r + 1) or - MicrobeSystem.getOrganelleAt(microbeEntity, hex.q + q - 1, hex.r + r + 0) then - touching = true; - end - end - - return touching -end - -function MicrobeSystem.splitOrganelle(microbeEntity, organelle) - local q = organelle.position.q - local r = organelle.position.r - - --Spiral search for space for the organelle - local radius = 1 - while true do - --Moves into the ring of radius "radius" and center the old organelle - q = q + HEX_NEIGHBOUR_OFFSET[HEX_SIDE.BOTTOM_LEFT][1] - r = r + HEX_NEIGHBOUR_OFFSET[HEX_SIDE.BOTTOM_LEFT][2] - - --Iterates in the ring - for side = 1, 6 do --necesary due to lua not ordering the tables. - local offset = HEX_NEIGHBOUR_OFFSET[side] - --Moves "radius" times into each direction - for i = 1, radius do - q = q + offset[1] - r = r + offset[2] - - --Checks every possible rotation value. - for j = 0, 5 do - local rotation = 360 * j / 6 - local data = {["name"]=organelle.name, ["q"]=q, ["r"]=r, ["rotation"]=i*60} - local newOrganelle = OrganelleFactory.makeOrganelle(data) - - if MicrobeSystem.validPlacement(microbeEntity, newOrganelle, q, r) then - print("placed " .. organelle.name .. " at " .. q .. " " .. r) - MicrobeSystem.addOrganelle(microbeEntity, q, r, i * 60, newOrganelle) - return newOrganelle - end - end - end - end - - radius = radius + 1 - end -end - --- Disables or enabled engulfmode for a microbe, allowing or disallowed it to absorb other microbes -function MicrobeSystem.toggleEngulfMode(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - local soundSourceComponent = getComponent(microbeEntity, SoundSourceComponent) - - if microbeComponent.engulfMode then - microbeComponent.movementFactor = microbeComponent.movementFactor * ENGULFING_MOVEMENT_DIVISION - soundSourceComponent:stopSound("microbe-engulfment") -- Possibly comment out. If version > 0.3.2 delete. --> We're way past 0.3.2, do we still need this? - rigidBodyComponent:reenableAllCollisions() - else - microbeComponent.movementFactor = microbeComponent.movementFactor / ENGULFING_MOVEMENT_DIVISION - end - - microbeComponent.engulfMode = not microbeComponent.engulfMode -end - --- Kills the microbe, releasing stored compounds into the enviroment -function MicrobeSystem.kill(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - local soundSourceComponent = getComponent(microbeEntity, SoundSourceComponent) - local microbeSceneNode = getComponent(microbeEntity, OgreSceneNodeComponent) - - -- Hacky but meh. - if microbeComponent.dead then return end - - -- Releasing all the agents. - for compoundId, _ in pairs(microbeComponent.specialStorageOrganelles) do - local _amount = MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) - while _amount > 0 do - ejectedAmount = MicrobeSystem.takeCompound(microbeEntity, compoundId, 3) -- Eject up to 3 units per particle - local direction = Vector3(math.random() * 2 - 1, math.random() * 2 - 1, 0) - createAgentCloud(compoundId, microbeSceneNode.transform.position.x, microbeSceneNode.transform.position.y, direction, amountToEject) - _amount = _amount - ejectedAmount - end - end - - local compoundsToRelease = {} - -- Eject the compounds that was in the microbe - for _, compoundId in pairs(CompoundRegistry.getCompoundList()) do - local total = MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) - local ejectedAmount = MicrobeSystem.takeCompound(microbeEntity, compoundId, total) - compoundsToRelease[compoundId] = ejectedAmount - end - - for _, organelle in pairs(microbeComponent.organelles) do - for compoundName, amount in pairs(organelleTable[organelle.name].composition) do - local compoundId = CompoundRegistry.getCompoundId(compoundName) - if(compoundsToRelease[compoundId] == nil) then - compoundsToRelease[compoundId] = amount * COMPOUND_RELEASE_PERCENTAGE - else - compoundsToRelease[compoundId] = compoundsToRelease[compoundId] + amount * COMPOUND_RELEASE_PERCENTAGE - end - end - end - - -- TODO: make the compounds be released inside of the microbe and not in the back. - for compoundId, amount in pairs(compoundsToRelease) do - MicrobeSystem.ejectCompound(microbeEntity, compoundId, amount) - end - - local deathAnimationEntity = Entity.new(g_luaEngine.currentGameState.wrapper) - local lifeTimeComponent = TimedLifeComponent.new() - lifeTimeComponent.timeToLive = 4000 - deathAnimationEntity:addComponent(lifeTimeComponent) - local deathAnimSceneNode = OgreSceneNodeComponent.new() - deathAnimSceneNode.meshName = "MicrobeDeath.mesh" - deathAnimSceneNode:playAnimation("Death", false) - deathAnimSceneNode.transform.position = Vector3(microbeSceneNode.transform.position.x, microbeSceneNode.transform.position.y, 0) - deathAnimSceneNode.transform:touch() - deathAnimationEntity:addComponent(deathAnimSceneNode) - soundSourceComponent:playSound("microbe-death") - microbeComponent.dead = true - microbeComponent.deathTimer = 5000 - microbeComponent.movementDirection = Vector3(0,0,0) - rigidBodyComponent:clearForces() - if not microbeComponent.isPlayerMicrobe then - for _, organelle in pairs(microbeComponent.organelles) do - organelle:removePhysics() - end - end - if microbeComponent.wasBeingEngulfed then - MicrobeSystem.removeEngulfedEffect(microbeEntity) - end - microbeSceneNode.visible = false -end - --- Damages the microbe, killing it if its hitpoints drop low enough --- --- @param amount --- amount of hitpoints to substract -function MicrobeSystem.damage(microbeEntity, amount, damageType) - assert(damageType ~= nil, "Damage type is nil") - assert(amount >= 0, "Can't deal negative damage. Use MicrobeSystem.heal instead") - - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local soundSourceComponent = getComponent(microbeEntity, SoundSourceComponent) - - if damageType == "toxin" then - soundSourceComponent:playSound("microbe-toxin-damage") - end - - -- Choose a random organelle or membrane to damage. - -- TODO: CHANGE TO USE AGENT CODES FOR DAMAGE. - local rand = math.random(1, microbeComponent.maxHitpoints/MICROBE_HITPOINTS_PER_ORGANELLE) - local i = 1 - for _, organelle in pairs(microbeComponent.organelles) do - -- If this is the organelle we have chosen... - if i == rand then - -- Deplete its health/compoundBin. - organelle:damageOrganelle(amount) - end - i = i + 1 - end - - -- Find out the amount of health the microbe has. - MicrobeSystem.calculateHealthFromOrganelles(microbeEntity) - - if microbeComponent.hitpoints <= 0 then - microbeComponent.hitpoints = 0 - MicrobeSystem.kill(microbeEntity) - end -end - --- Damage the microbe if its too low on ATP. -function MicrobeSystem.atpDamage(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - - if MicrobeSystem.getCompoundAmount(microbeEntity, CompoundRegistry.getCompoundId("atp")) < 1.0 then - -- TODO: put this on a GUI notification. - --[[ - if microbeComponent.isPlayerMicrobe and not self.playerAlreadyShownAtpDamage then - self.playerAlreadyShownAtpDamage = true - showMessage("No ATP hurts you!") - end - ]] - MicrobeSystem.damage(microbeEntity, EXCESS_COMPOUND_COLLECTION_INTERVAL * 0.000002 * microbeComponent.maxHitpoints, "atpDamage") -- Microbe takes 2% of max hp per second in damage - end -end - --- Drains an agent from the microbes special storage and emits it --- --- @param compoundId --- The compound id of the agent to emit --- --- @param maxAmount --- The maximum amount to try to emit -function MicrobeSystem.emitAgent(microbeEntity, compoundId, maxAmount) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local sceneNodeComponent = getComponent(microbeEntity, OgreSceneNodeComponent) - local soundSourceComponent = getComponent(microbeEntity, SoundSourceComponent) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - - -- Cooldown code - if microbeComponent.agentEmissionCooldown > 0 then return end - local numberOfAgentVacuoles = microbeComponent.specialStorageOrganelles[compoundId] - - -- Only shoot if you have agent vacuoles. - if numberOfAgentVacuoles == nil or numberOfAgentVacuoles == 0 then return end - - -- The cooldown time is inversely proportional to the amount of agent vacuoles. - microbeComponent.agentEmissionCooldown = AGENT_EMISSION_COOLDOWN / numberOfAgentVacuoles - - if MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) > MINIMUM_AGENT_EMISSION_AMOUNT then - soundSourceComponent:playSound("microbe-release-toxin") - - -- Calculate the emission angle of the agent emitter - local organelleX, organelleY = axialToCartesian(0, -1) -- The front of the microbe - local membraneCoords = membraneComponent:getExternOrganellePos(organelleX, organelleY) - - local angle = math.atan2(organelleY, organelleX) - if (angle < 0) then - angle = angle + 2*math.pi - end - angle = -(angle * 180/math.pi -90 ) % 360 - --angle = angle * 180/math.pi - - -- Find the direction the microbe is facing - local yAxis = sceneNodeComponent.transform.orientation:yAxis() - local microbeAngle = math.atan2(yAxis.x, yAxis.y) - if (microbeAngle < 0) then - microbeAngle = microbeAngle + 2*math.pi - end - microbeAngle = microbeAngle * 180/math.pi - -- Take the microbe angle into account so we get world relative degrees - local finalAngle = (angle + microbeAngle) % 360 - - local s = math.sin(finalAngle/180*math.pi); - local c = math.cos(finalAngle/180*math.pi); - - local xnew = -membraneCoords[1] * c + membraneCoords[2] * s; - local ynew = membraneCoords[1] * s + membraneCoords[2] * c; - - local direction = Vector3(xnew, ynew, 0) - direction:normalise() - local amountToEject = MicrobeSystem.takeCompound(microbeEntity, compoundId, maxAmount/10.0) - createAgentCloud(compoundId, sceneNodeComponent.transform.position.x + xnew, sceneNodeComponent.transform.position.y + ynew, direction, amountToEject * 10) - end -end - -function MicrobeSystem.transferCompounds(fromEntity, toEntity) - for _, compoundID in pairs(CompoundRegistry.getCompoundList()) do - local amount = MicrobeSystem.getCompoundAmount(fromEntity, compoundID) - - if amount ~= 0 then - MicrobeSystem.takeCompound(fromEntity, compoundID, amount, false) - MicrobeSystem.storeCompound(toEntity, compoundID, amount, false) - end - end -end - --- Creates a new microbe with all required components --- --- @param name --- The entity's name. If nil, the entity will be unnamed. --- --- @returns microbe --- An object of type Microbe - -function MicrobeSystem.createMicrobeEntity(name, aiControlled, speciesName, in_editor) - assert(isNotEmpty(speciesName)) - - local entity - if name then - entity = Entity.new(name, g_luaEngine.currentGameState.wrapper) - else - entity = Entity.new(g_luaEngine.currentGameState.wrapper) - end - - local rigidBody = RigidBodyComponent.new() - rigidBody.properties.shape = CompoundShape.new() - rigidBody.properties.linearDamping = 0.5 - rigidBody.properties.friction = 0.2 - rigidBody.properties.mass = 0.0 - rigidBody.properties.linearFactor = Vector3(1, 1, 0) - rigidBody.properties.angularFactor = Vector3(0, 0, 1) - rigidBody.properties:touch() - - local reactionHandler = CollisionComponent.new() - reactionHandler:addCollisionGroup("microbe") - - local membraneComponent = MembraneComponent.new() - - local soundComponent = SoundSourceComponent.new() - local s1 = nil - soundComponent:addSound("microbe-release-toxin", "soundeffects/microbe-release-toxin.ogg") - soundComponent:addSound("microbe-toxin-damage", "soundeffects/microbe-toxin-damage.ogg") - soundComponent:addSound("microbe-death", "soundeffects/microbe-death.ogg") - soundComponent:addSound("microbe-pickup-organelle", "soundeffects/microbe-pickup-organelle.ogg") - soundComponent:addSound("microbe-engulfment", "soundeffects/engulfment.ogg") - soundComponent:addSound("microbe-reproduction", "soundeffects/reproduction.ogg") - - s1 = soundComponent:addSound("microbe-movement-1", "soundeffects/microbe-movement-1.ogg") - s1.properties.volume = 0.4 - s1.properties:touch() - s1 = soundComponent:addSound("microbe-movement-turn", "soundeffects/microbe-movement-2.ogg") - s1.properties.volume = 0.1 - s1.properties:touch() - s1 = soundComponent:addSound("microbe-movement-2", "soundeffects/microbe-movement-3.ogg") - s1.properties.volume = 0.4 - s1.properties:touch() - - local components = { - CompoundAbsorberComponent.new(), - OgreSceneNodeComponent.new(), - CompoundBagComponent.new(), - MicrobeComponent.new(not aiControlled, speciesName), - reactionHandler, - rigidBody, - soundComponent, - membraneComponent - } - - if aiControlled then - local aiController = MicrobeAIControllerComponent.new() - table.insert(components, aiController) - end - - for _, component in ipairs(components) do - entity:addComponent(component) - end - - MicrobeSystem.initializeMicrobe(entity, in_editor, g_luaEngine.currentGameState) - - return entity -end - -function MicrobeSystem.calculateStorageSpace(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - - microbeComponent.stored = 0 - for _, compoundId in pairs(CompoundRegistry.getCompoundList()) do - microbeComponent.stored = microbeComponent.stored + MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) - end -end - --- Private function for updating the compound absorber --- --- Toggles the absorber on and off depending on the remaining storage --- capacity of the storage organelles. -function MicrobeSystem.updateCompoundAbsorber(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local compoundAbsorberComponent = getComponent(microbeEntity, CompoundAbsorberComponent) - - if --microbeComponent.stored >= microbeComponent.capacity or - microbeComponent.remainingBandwidth < 1 or - microbeComponent.dead then - compoundAbsorberComponent:disable() - else - compoundAbsorberComponent:enable() - end -end - -function MicrobeSystem.divide(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local soundSourceComponent = getComponent(microbeEntity, SoundSourceComponent) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - - -- Create the two daughter cells. - local copyEntity = MicrobeSystem.createMicrobeEntity(nil, true, microbeComponent.speciesName, false) - local microbeComponentCopy = getComponent(copyEntity, MicrobeComponent) - local rigidBodyComponentCopy = getComponent(copyEntity, RigidBodyComponent) - - --Separate the two cells. - rigidBodyComponentCopy.dynamicProperties.position = Vector3(rigidBodyComponent.dynamicProperties.position.x - membraneComponent.dimensions/2, rigidBodyComponent.dynamicProperties.position.y, 0) - rigidBodyComponent.dynamicProperties.position = Vector3(rigidBodyComponent.dynamicProperties.position.x + membraneComponent.dimensions/2, rigidBodyComponent.dynamicProperties.position.y, 0) - - -- Split the compounds evenly between the two cells. - for _, compoundID in pairs(CompoundRegistry.getCompoundList()) do - local amount = MicrobeSystem.getCompoundAmount(microbeEntity, compoundID) - - if amount ~= 0 then - MicrobeSystem.takeCompound(microbeEntity, compoundID, amount / 2, false) - MicrobeSystem.storeCompound(copyEntity, compoundID, amount / 2, false) - end - end - - microbeComponent.reproductionStage = 0 - microbeComponentCopy.reproductionStage = 0 - - local spawnedComponent = SpawnedComponent.new() - spawnedComponent:setSpawnRadius(MICROBE_SPAWN_RADIUS) - copyEntity:addComponent(spawnedComponent) - soundSourceComponent:playSound("microbe-reproduction") -end - --- Copies this microbe. The new microbe will not have the stored compounds of this one. -function MicrobeSystem.readyToReproduce(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - - if microbeComponent.isPlayerMicrobe then - showReproductionDialog() - microbeComponent.reproductionStage = 0 - else - -- Return the first cell to its normal, non duplicated cell arangement. - SpeciesSystem.template(microbeEntity, MicrobeSystem.getSpeciesComponent(microbeEntity)) - MicrobeSystem.divide(microbeEntity) - end -end - --- Updates the microbe's state -function MicrobeSystem.updateMicrobe(microbeEntity, logicTime) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - local sceneNodeComponent = getComponent(microbeEntity, OgreSceneNodeComponent) - local compoundAbsorberComponent = getComponent(microbeEntity, CompoundAbsorberComponent) - local compoundBag = getComponent(microbeEntity, CompoundBagComponent) - - if not microbeComponent.dead then - -- Recalculating agent cooldown time. - microbeComponent.agentEmissionCooldown = math.max(microbeComponent.agentEmissionCooldown - logicTime, 0) - - --calculate storage. - MicrobeSystem.calculateStorageSpace(microbeEntity) - - compoundBag.storageSpace = microbeComponent.capacity - - -- StorageOrganelles - MicrobeSystem.updateCompoundAbsorber(microbeEntity) - -- Regenerate bandwidth - MicrobeSystem.regenerateBandwidth(microbeEntity, logicTime) - -- Attempt to absorb queued compounds - for _, compound in pairs(compoundAbsorberComponent:getAbsorbedCompounds()) do - local amount = compoundAbsorberComponent:absorbedCompoundAmount(compound) - if amount > 0.0 then - MicrobeSystem.storeCompound(microbeEntity, compound, amount, true) - end - end - -- Flash membrane if something happens. - if microbeComponent.flashDuration ~= nil and microbeComponent.flashColour ~= nil then - microbeComponent.flashDuration = microbeComponent.flashDuration - logicTime - - local entity = membraneComponent.entity - -- How frequent it flashes, would be nice to update the flash function to have this variable - if math.fmod(microbeComponent.flashDuration, 600) < 300 then - entity:tintColour("Membrane", microbeComponent.flashColour) - else - entity:setMaterial(sceneNodeComponent.meshName) - end - - if microbeComponent.flashDuration <= 0 then - microbeComponent.flashDuration = nil - entity:setMaterial(sceneNodeComponent.meshName) - end - end - - microbeComponent.compoundCollectionTimer = microbeComponent.compoundCollectionTimer + logicTime - while microbeComponent.compoundCollectionTimer > EXCESS_COMPOUND_COLLECTION_INTERVAL do - -- For every COMPOUND_DISTRIBUTION_INTERVAL passed - - microbeComponent.compoundCollectionTimer = microbeComponent.compoundCollectionTimer - EXCESS_COMPOUND_COLLECTION_INTERVAL - - MicrobeSystem.purgeCompounds(microbeEntity) - - MicrobeSystem.atpDamage(microbeEntity) - end - - -- First organelle run: updates all the organelles and heals the broken ones. - if microbeComponent.hitpoints < microbeComponent.maxHitpoints then - for _, organelle in pairs(microbeComponent.organelles) do - -- Update the organelle. - organelle:update(logicTime) - - -- If the organelle is hurt. - if organelle:getCompoundBin() < 1.0 then - -- Give the organelle access to the compound bag to take some compound. - organelle:growOrganelle(getComponent(microbeEntity, CompoundBagComponent), logicTime) - -- An organelle was damaged and we tried to heal it, so out health might be different. - MicrobeSystem.calculateHealthFromOrganelles(microbeEntity) - end - end - else - - local reproductionStageComplete = true - local organellesToAdd = {} - - -- Grow all the large organelles. - for _, organelle in pairs(microbeComponent.organelles) do - -- Update the organelle. - organelle:update(logicTime) - - -- We are in G1 phase of the cell cycle, duplicate all organelles. - if organelle.name ~= "nucleus" and microbeComponent.reproductionStage == 0 then - - -- If the organelle is not split, give it some compounds to make it larger. - if organelle:getCompoundBin() < 2.0 and not organelle.wasSplit then - -- Give the organelle access to the compound bag to take some compound. - organelle:growOrganelle(getComponent(microbeEntity, CompoundBagComponent), logicTime) - reproductionStageComplete = false - -- If the organelle was split and has a bin less then 1, it must have been damaged. - elseif organelle:getCompoundBin() < 1.0 and organelle.wasSplit then - -- Give the organelle access to the compound bag to take some compound. - organelle:growOrganelle(getComponent(microbeEntity, CompoundBagComponent), logicTime) - -- If the organelle is twice its size... - elseif organelle:getCompoundBin() >= 2.0 then - --Queue this organelle for splitting after the loop. - --(To avoid "cutting down the branch we're sitting on"). - table.insert(organellesToAdd, organelle) - end - - -- In the S phase, the nucleus grows as chromatin is duplicated. - elseif organelle.name == "nucleus" and microbeComponent.reproductionStage == 1 then - -- If the nucleus hasn't finished replicating its DNA, give it some compounds. - if organelle:getCompoundBin() < 2.0 then - -- Give the organelle access to the compound back to take some compound. - organelle:growOrganelle(getComponent(microbeEntity, CompoundBagComponent), logicTime) - reproductionStageComplete = false - end - end - - end - - --Splitting the queued organelles. - for _, organelle in pairs(organellesToAdd) do - print("ready to split " .. organelle.name) - -- Mark this organelle as done and return to its normal size. - organelle:reset() - organelle.wasSplit = true - -- Create a second organelle. - local organelle2 = MicrobeSystem.splitOrganelle(microbeEntity, organelle) - organelle2.wasSplit = true - organelle2.isDuplicate = true - organelle2.sisterOrganelle = organelle - - -- Redo the cell membrane. - membraneComponent:clear() - end - - if reproductionStageComplete and microbeComponent.reproductionStage < 2 then - microbeComponent.reproductionStage = microbeComponent.reproductionStage + 1 - end - - -- To finish the G2 phase we just need more than a threshold of compounds. - if microbeComponent.reproductionStage == 2 or microbeComponent.reproductionStage == 3 then - MicrobeSystem.readyToReproduce(microbeEntity) - end - end - - if microbeComponent.engulfMode then - -- Drain atp and if we run out then disable engulfmode - local cost = ENGULFING_ATP_COST_SECOND/1000*logicTime - - if MicrobeSystem.takeCompound(microbeEntity, CompoundRegistry.getCompoundId("atp"), cost) < cost - 0.001 then - print ("too little atp, disabling - 749") - MicrobeSystem.toggleEngulfMode(microbeEntity) - end - -- Flash the membrane blue. - MicrobeSystem.flashMembraneColour(microbeEntity, 3000, ColourValue(0.2,0.5,1.0,0.5)) - end - if microbeComponent.isBeingEngulfed and microbeComponent.wasBeingEngulfed then - MicrobeSystem.damage(microbeEntity, logicTime * 0.000025 * microbeComponent.maxHitpoints, "isBeingEngulfed - Microbe:update()s") - -- Else If we were but are no longer, being engulfed - elseif microbeComponent.wasBeingEngulfed then - MicrobeSystem.removeEngulfedEffect(microbeEntity) - end - -- Used to detect when engulfing stops - microbeComponent.isBeingEngulfed = false; - compoundAbsorberComponent:setAbsorbtionCapacity(math.min(microbeComponent.capacity - microbeComponent.stored + 10, microbeComponent.remainingBandwidth)) - else - microbeComponent.deathTimer = microbeComponent.deathTimer - logicTime - microbeComponent.flashDuration = 0 - if microbeComponent.deathTimer <= 0 then - if microbeComponent.isPlayerMicrobe == true then - MicrobeSystem.respawnPlayer() - else - for _, organelle in pairs(microbeComponent.organelles) do - organelle:onRemovedFromMicrobe() - end - microbeEntity:destroy() - end - end - end -end - --- Microbe entity initializer --- --- Requires all necessary components (see MICROBE_COMPONENTS) to be present in --- the entity. --- --- @param entity --- The entity this microbe wraps -function MicrobeSystem.initializeMicrobe(microbeEntity, in_editor) - -- Checking if the entity exists. - assert(microbeEntity ~= nil) - - -- Checking if all the components are there. - for key, ctype in pairs(MICROBE_COMPONENTS) do - local component = getComponent(microbeEntity, ctype) - assert(component ~= nil, "Can't create microbe from this entity, it's missing " .. key) - end - - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local compoundAbsorberComponent = getComponent(microbeEntity, CompoundAbsorberComponent) - local compoundBag = getComponent(microbeEntity, CompoundBagComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - local sceneNodeComponent = getComponent(microbeEntity, OgreSceneNodeComponent) - - -- Allowing the microbe to absorb all the compounds. - for _, compound in pairs(CompoundRegistry.getCompoundList()) do - compoundAbsorberComponent:setCanAbsorbCompound(compound, true) - end - - if not microbeComponent.initialized then - -- TODO: cache for performance - local compoundShape = CompoundShape.castFrom(rigidBodyComponent.properties.shape) - assert(compoundShape ~= nil) - compoundShape:clear() - rigidBodyComponent.properties.mass = 0.0 - - -- Organelles - for s, organelle in pairs(microbeComponent.organelles) do - organelle:onAddedToMicrobe(microbeEntity, organelle.position.q, organelle.position.r, organelle.rotation) - organelle:reset() - rigidBodyComponent.properties.mass = rigidBodyComponent.properties.mass + organelle.mass - end - - -- Membrane - sceneNodeComponent.meshName = "membrane_" .. microbeComponent.speciesName - rigidBodyComponent.properties:touch() - microbeComponent.initialized = true - - if in_editor ~= true then - assert(microbeComponent.speciesName) - - local processor = getComponent(microbeComponent.speciesName, - g_luaEngine.currentGameState, - ProcessorComponent) - - if processor == nil then - print("Microbe species '" .. microbeComponent.speciesName .. "' doesn't exist") - assert(processor) - end - - assert(isNotEmpty(microbeComponent.speciesName)) - compoundBag:setProcessor(processor, microbeComponent.speciesName) - - SpeciesSystem.template(microbeEntity, MicrobeSystem.getSpeciesComponent(microbeEntity)) - end - end - MicrobeSystem.updateCompoundAbsorber(microbeEntity) -end diff --git a/scripts/microbe_stage/microbe_ai.as b/scripts/microbe_stage/microbe_ai.as new file mode 100644 index 00000000000..90d34a35994 --- /dev/null +++ b/scripts/microbe_stage/microbe_ai.as @@ -0,0 +1,380 @@ + + +const int OXYGEN_SEARCH_THRESHHOLD = 8; +const int GLUCOSE_SEARCH_THRESHHOLD = 5; +const float AI_MOVEMENT_SPEED = 0.5; + +// microbes_number = {} + +//////////////////////////////////////////////////////////////////////////////// +// MicrobeAIControllerComponent +// +// Component for identifying and determining AI controlled microbes. +//////////////////////////////////////////////////////////////////////////////// +class MicrobeAIControllerComponent : ScriptComponent{ + + MicrobeAIControllerComponent(){ + + intervalRemaining = reevalutationInterval; + } + + int movementRadius = 20; + int reevalutationInterval = 1000; + int intervalRemaining; + Float3 direction = Float3(0, 0, 0); + bool hasTargetEmitterPosition = false; + Float3 targetEmitterPosition = Float3(0, 0, 0); + bool hasSearchedCompoundId = false; + CompoundId searchedCompoundId; + ObjectID prey = NULL_OBJECT; +} + +// void MicrobeAIControllerComponent.storage(storage){ + +// storage.set("movementRadius", this.movementRadius); +// storage.set("reevalutationInterval", this.reevalutationInterval); +// storage.set("intervalRemaining", this.intervalRemaining); +// storage.set("direction", this.direction); +// if(this.targetEmitterPosition == null){ +// storage.set("targetEmitterPosition", "null"); +// else; +// storage.set("targetEmitterPosition", this.targetEmitterPosition); +// } +// if(this.searchedCompoundId == null){ +// storage.set("searchedCompoundId", "null"); +// else; +// storage.set("searchedCompoundId", this.searchedCompoundId); +// } + +// } + +// void MicrobeAIControllerComponent.load(storage){ + +// this.movementRadius = storage.get("movementRadius", 20); +// this.reevalutationInterval = storage.get("reevalutationInterval", 1000); +// this.intervalRemaining = storage.get("intervalRemaining", this.reevalutationInterval); +// this.direction = storage.get("direction", Vector3(0, 0, 0)); +// auto emitterPosition = storage.get("targetEmitterPosition", null); +// if(emitterPosition == "null"){ +// this.targetEmitterPosition = null; +// else; +// this.targetEmitterPosition = emitterPosition; +// } +// this.searchedCompoundId = storage.get("searchedCompoundId", null); +// if(this.searchedCompoundId == "null"){ +// this.searchedCompoundId = null; +// } +// } + +//! \todo Check if there is a better way than caching a single component for this system +class MicrobeAISystemCached{ + + MicrobeAISystemCached(ObjectID entity, MicrobeAIControllerComponent@ first, + MicrobeComponent@ second, Position@ third + ) { + + this.entity = entity; + @this.first = first; + @this.second = second; + @this.third = third; + } + + ObjectID entity = -1; + + MicrobeAIControllerComponent@ first; + MicrobeComponent@ second; + Position@ third; +} + +//////////////////////////////////////////////////////////////////////////////// +// MicrobeAISystem +// +// Updates AI controlled microbes +//////////////////////////////////////////////////////////////////////////////// +class MicrobeAISystem : ScriptSystem{ + + void Init(GameWorld@ w){ + + @this.world = cast(w); + assert(this.world !is null, "MicrobeAISystem expected CellStageWorld"); + } + + void Release(){} + + void Run(){ + // for(_, entityId in pairs(this.entities.removedEntities())){ + // this.microbes[entityId] = null; + // if(this.preyEntityToIndexMap[entityId]){ + // this.preyCandidates[this.preyEntityToIndexMap[entityId]] = null; + // this.preyEntityToIndexMap[entityId] = null; + // } + // } + // for(_, entityId in pairs(this.entities.addedEntities())){ + // auto microbeEntity = Entity(entityId, this.gameState.wrapper); + // this.microbes[entityId] = microbeEntity; + + // // This is a hack to remember up to 5 recent microbes as candidates for predators. + // // Gives something semi random + // this.preyCandidates[this.currentPreyIndex] = microbeEntity; + // this.preyEntityToIndexMap[entityId] = this.currentPreyIndex; + // this.currentPreyIndex = (this.currentPreyIndex)%6; + + // } + + // //for removing cell from table when it is removed from the world + // for(_, entityId in pairs(this.microbeEntities.removedEntities())){ + // microbes_number[entityId] = null; + // } + + // //for counting all the cells in the world and get it's entity + // for(_, entityId in pairs(this.microbeEntities.addedEntities())){ + // auto microbeEntity = Entity(entityId, this.gameState.wrapper); + // microbes_number[entityId] = microbeEntity; + // } + + // this.entities.clearChanges(); + // this.microbeEntities.clearChanges(); + + const int logicTime = TICKSPEED; + + // TODO: this could be cached better + CompoundId oxytoxyId = SimulationParameters::compoundRegistry().getTypeId("oxytoxy"); + + // This list is quite expensive to build each frame but + // there's currently no good way to cache this + array@ allMicrobes = world.GetScriptComponentHolder( + "MicrobeComponent").GetIndex(); + + for(uint i = 0; i < CachedComponents.length(); ++i){ + + MicrobeAISystemCached@ components = CachedComponents[i]; + + ObjectID microbeEntity = components.entity; + + MicrobeAIControllerComponent@ aiComponent = components.first; + MicrobeComponent@ microbeComponent = components.second; + Position@ position = components.third; + + aiComponent.intervalRemaining += logicTime; + while(aiComponent.intervalRemaining > aiComponent.reevalutationInterval) { + + aiComponent.intervalRemaining -= aiComponent.reevalutationInterval; + + Float3 targetPosition = Float3(0, 0, 0); + int numberOfAgentVacuoless = int( + microbeComponent.specialStorageOrganelles[formatUInt(oxytoxyId)]); + + // //for getting the prey + // for(m_microbeEntityId, in pairs (microbes_number)){ + + // // The m_ prefix is used here for some bizarre reason + // // m_microbeEntity + + // MicrobeComponent@ m_microbeComponent = cast( + // world.GetScriptComponentHolder("MicrobeComponent").Find(m_microbeEntity)); + + // auto m_position = world.GetComponent_RenderNode(m_microbeEntity); + + // if(this.preys !is null){ + // auto v = (m_position.transform.position - + // position.transform.position); + + // if(v.length() < 25 and v.length() ~= 0 ){ + // if(microbeComponent.maxHitpoints > 1.5 * + // m_microbeComponent.maxHitpoints) + // { + // this.preys[m_microbeEntityId] = m_microbeEntity; + // } + + // if(numberOfAgentVacuoles !is null and numberOfAgentVacuoles ~= 0 + // and (m_microbeComponent.specialStorageOrganelles[oxytoxyId] == null + // or m_microbeComponent.specialStorageOrganelles[oxytoxyId] == 0) + // and this.preys[m_microbeEntityId] == null){ + + // this.preys[m_microbeEntityId] = m_microbeEntity; + // } + // } else if(v.length() > 25 or v.length() == 0){ + // this.preys[m_microbeEntityId] = null; + // } + // if(this.preys[m_microbeEntityId] !is null){ + // preyMicrobeComponent = getComponent(this.preys[m_microbeEntityId], MicrobeComponent); + // if(preyMicrobeComponent.maxHitpoints <= this.preyMaxHitpoints){ + // this.preyMaxHitpoints = preyMicrobeComponent.maxHitpoints; + // this.p = this.preys[m_microbeEntityId]; + // } + // this.preycount = this.preycount + 1; + // } + // } + // } + + // //for getting the predator + // for(predatorEntityId, predatorEntity in pairs (microbes_number)){ + // auto predatorMicrobeComponent = getComponent(predatorEntity, MicrobeComponent); + // auto predatorSceneNodeComponent = getComponent(predatorEntity, OgreSceneNodeComponent); + + // auto vec = (predatorSceneNodeComponent.transform.position - + // position.transform.position); + // if(predatorMicrobeComponent.maxHitpoints > microbeComponent.maxHitpoints + // * 1.5 and vec.length() < 25) + // { + // this.predators[predatorEntityId] = predatorEntity; + // } + // if (predatorMicrobeComponent.specialStorageOrganelles[oxytoxyId] !is null + // and predatorMicrobeComponent.specialStorageOrganelles[oxytoxyId] ~= 0 + // and (numberOfAgentVacuoles == null or numberOfAgentVacuoles == 0) and + // vec.length() < 25) + // { + // this.predators[predatorEntityId] = predatorEntity; + // } + // if(vec.length() > 25){ + // this.predators[predatorEntityId] = null; + // } + // this.predator = this.predators[predatorEntityId]; + // } + + // if(numberOfAgentVacuoles > 0 || microbeComponent.maxHitpoints > 100){ + // this.preyCandidates[6] = Entity(PLAYER_NAME, this.gameState.wrapper); + // this.preyEntityToIndexMap[Entity(PLAYER_NAME, this.gameState.wrapper).id] = 6; + // auto attempts = 0; + // while (aiComponent.prey == null or not aiComponent.prey.exists() + // or getComponent( aiComponent.prey, MicrobeComponent) == null + // or getComponent( aiComponent.prey, MicrobeComponent).dead + // or (getComponent(aiComponent.prey, MicrobeComponent).speciesName == + // microbeComponent.speciesName) + // or this.preyEntityToIndexMap[aiComponent.prey.id] == null or + // this.preyEscaped == true and attempts < 6 and this.preycount > 10) + // { + // aiComponent.prey = this.p; //setting the prey + // attempts = attempts + 1; + // this.preyEscaped = false; + // } + + // if(this.predator !is null){ // for running away from the predadtor + // auto predatorSceneNodeComponent = getComponent(this.predator, + // OgreSceneNodeComponent); + // microbeComponent.facingTargetPoint = + // Vector3(-predatorSceneNodeComponent.transform.position.x, + // -predatorSceneNodeComponent.transform.position.y, 0); + // microbeComponent.movementDirection = Vector3(0, AI_MOVEMENT_SPEED, 0); + // } + + // if(attempts < 6 and aiComponent.prey !is null and this.predator == null){ + // //making sure it is not a prey for someone before start hunting + // auto preyMicrobeComponent = getComponent(aiComponent.prey, + // MicrobeComponent); + // auto preySceneNodeComponent = getComponent(aiComponent.prey, + // OgreSceneNodeComponent); + + // vec = (preySceneNodeComponent.transform.position - + // position.transform.position); + // if(vec.length() > 25){ + // this.preyEscaped = true; + // } + // if(vec.length() < 25 and vec.length() > 10 + // and MicrobeSystem.getCompoundAmount(microbeEntity, oxytoxyId) > MINIMUM_AGENT_EMISSION_AMOUNT + // and microbeComponent.microbetargetdirection < 10){ + + + // MicrobeSystem.emitAgent(microbeEntity, + // CompoundRegistry.getCompoundId("oxytoxy"), 1); + // } else if(vec.length() < 10 + // and microbeComponent.maxHitpoints > ENGULF_HP_RATIO_REQ * preyMicrobeComponent.maxHitpoints; + // and not microbeComponent.engulfMode){ + // MicrobeSystem.toggleEngulfMode(microbeEntity); + // } else if(vec.length() > 15 and microbeComponent.engulfMode){ + // MicrobeSystem.toggleEngulfMode(microbeEntity); + // } + + // vec.normalise(); + // aiComponent.direction = vec; + // microbeComponent.facingTargetPoint = + // Vector3(preySceneNodeComponent.transform.position.x, + // preySceneNodeComponent.transform.position.y, 0); + // microbeComponent.movementDirection = Vector3(0, AI_MOVEMENT_SPEED, 0); + // } + // } else { + // if(MicrobeSystem.getCompoundAmount(microbeEntity, + // CompoundRegistry.getCompoundId("oxygen")) <= OXYGEN_SEARCH_THRESHHOLD) + // { + // // If we are NOT currenty heading towards an emitter + // // emitters were removed a long time ago... + // } + // } + + // targetPosition = aiComponent.targetEmitterPosition; + // if(aiComponent.targetEmitterPosition !is null and + // aiComponent.targetEmitterPosition.z ~= 0){ + // aiComponent.targetEmitterPosition = null; + // } + // } else if(MicrobeSystem.getCompoundAmount(microbeEntity, + // CompoundRegistry.getCompoundId("glucose")) <= GLUCOSE_SEARCH_THRESHHOLD) + // { + // // If we are NOT currenty heading towards an emitter + + // } + + + // I guess this part just makes the AI move randomly + // if(aiComponent.targetEmitterPosition == null){ + auto randAngle = GetEngine().GetRandom().GetFloat(0, 2*PI); + auto randDist = GetEngine().GetRandom().GetFloat(10, + aiComponent.movementRadius); + + targetPosition = Float3(cos(randAngle) * randDist, + 0, sin(randAngle)* randDist); + // } + auto vec = (targetPosition - position._Position); + aiComponent.direction = vec.Normalize(); + microbeComponent.facingTargetPoint = targetPosition; + microbeComponent.movementDirection = Float3(0, 0, -AI_MOVEMENT_SPEED); + } + } + } + + void Clear(){ + + CachedComponents.resize(0); + } + + void CreateAndDestroyNodes(){ + + // Delegate to helper // + ScriptSystemNodeHelper(world, @CachedComponents, SystemComponents); + } + + private array CachedComponents; + private CellStageWorld@ world; + + private array SystemComponents = { + ScriptSystemUses("MicrobeAIControllerComponent"), + ScriptSystemUses("MicrobeComponent"), + ScriptSystemUses(Position::TYPE) + }; + + // This isn't currently possible to store + // dictionary microbes = {}; + + // It's really silly to have these here instead of in the AI + // component, like what system tries to store most of its state in + // itself instead of its components? + // dictionary preyCandidates = {}; + // // Used for removing from preyCandidates + // dictionary preyEntityToIndexMap = {}; + // int currentPreyIndex = 0; + // //table for preys + // dictionary preys = {}; + // //the final prey the cell should hunt + // ObjectID p = NULL_OBJECT; + // //counting number of frames so the prey get updated the fittest prey + // int preycount = 0; + // //checking if the prey escaped + // bool preyEscaped = false; + // //table for predadtors the cell should run from + // dictionary predators = {}; + // //the final predator the cell shall run from + // ObjectID predator = NULL_OBJECT; + + //i need it to be very big for now it will get changed + int preyMaxHitpoints = 100000; + +} diff --git a/scripts/microbe_stage/microbe_ai.lua b/scripts/microbe_stage/microbe_ai.lua deleted file mode 100644 index 08fac31caf5..00000000000 --- a/scripts/microbe_stage/microbe_ai.lua +++ /dev/null @@ -1,352 +0,0 @@ --------------------------------------------------------------------------------- --- MicrobeAIControllerComponent --- --- Component for identifying and determining AI controlled microbes. --------------------------------------------------------------------------------- - -OXYGEN_SEARCH_THRESHHOLD = 8 -GLUCOSE_SEARCH_THRESHHOLD = 5 -AI_MOVEMENT_SPEED = 0.5 -microbes_number = {} -MicrobeAIControllerComponent = class( - function(self) - self.movementRadius = 20 - self.reevalutationInterval = 1000 - self.intervalRemaining = self.reevalutationInterval - self.direction = Vector3(0, 0, 0) - self.targetEmitterPosition = nil - self.searchedCompoundId = nil - self.prey = nil - end -) - -MicrobeAIControllerComponent.TYPE_NAME = "MicrobeAIControllerComponent" - -function MicrobeAIControllerComponent:storage(storage) - - storage:set("movementRadius", self.movementRadius) - storage:set("reevalutationInterval", self.reevalutationInterval) - storage:set("intervalRemaining", self.intervalRemaining) - storage:set("direction", self.direction) - if self.targetEmitterPosition == nil then - storage:set("targetEmitterPosition", "nil") - else - storage:set("targetEmitterPosition", self.targetEmitterPosition) - end - if self.searchedCompoundId == nil then - storage:set("searchedCompoundId", "nil") - else - storage:set("searchedCompoundId", self.searchedCompoundId) - end - -end - -function MicrobeAIControllerComponent:load(storage) - - self.movementRadius = storage:get("movementRadius", 20) - self.reevalutationInterval = storage:get("reevalutationInterval", 1000) - self.intervalRemaining = storage:get("intervalRemaining", self.reevalutationInterval) - self.direction = storage:get("direction", Vector3(0, 0, 0)) - local emitterPosition = storage:get("targetEmitterPosition", nil) - if emitterPosition == "nil" then - self.targetEmitterPosition = nil - else - self.targetEmitterPosition = emitterPosition - end - self.searchedCompoundId = storage:get("searchedCompoundId", nil) - if self.searchedCompoundId == "nil" then - self.searchedCompoundId = nil - end -end - -REGISTER_COMPONENT("MicrobeAIControllerComponent", MicrobeAIControllerComponent) - - --------------------------------------------------------------------------------- --- MicrobeAISystem --- --- Updates AI controlled microbes --------------------------------------------------------------------------------- - -MicrobeAISystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - - self.entities = EntityFilter.new( - { - MicrobeAIControllerComponent, - MicrobeComponent - }, - true - ) - self.emitters = EntityFilter.new( - { - CompoundEmitterComponent - }, - true - ) - self.microbeEntities = EntityFilter.new( - { - MicrobeComponent - }, -true - ) -self.microbes = {} - self.preyCandidates = {} - self.preyEntityToIndexMap = {} -- Used for removing from preyCandidates - self.currentPreyIndex = 0 - self.oxygenEmitters = {} - self.glucoseEmitters = {} - self.preys = {} --table for preys - self.p = nil --the final prey the cell should hunt - self.preyMaxHitpoints = 100000 --i need it to be very big for now it will get changed - self.preycount = 0 --counting number of frames so the prey get updated the fittest prey - self.preyEscaped = false --checking if the prey escaped - self.predators = {} --table for predadtors the cell should run from - self.predator = nil --the final predator the cell shall run from - end -) - -function MicrobeAISystem:init(gameState) - LuaSystem.init(self, "MicrobeAISystem", gameState) - self.entities:init(gameState.wrapper) - self.emitters:init(gameState.wrapper) - self.microbeEntities:init(gameState.wrapper) -end - - -function MicrobeAISystem:shutdown() - LuaSystem.shutdown(self) - self.entities:shutdown() - self.emitters:shutdown() - self.microbeEntities:shutdown() -end - -function MicrobeAISystem:update(renderTime, logicTime) - for _, entityId in pairs(self.entities:removedEntities()) do - self.microbes[entityId] = nil - if self.preyEntityToIndexMap[entityId] then - self.preyCandidates[self.preyEntityToIndexMap[entityId]] = nil - self.preyEntityToIndexMap[entityId] = nil - end - end - for _, entityId in pairs(self.entities:addedEntities()) do - local microbeEntity = Entity.new(entityId, self.gameState.wrapper) - self.microbes[entityId] = microbeEntity - - -- This is a hack to remember up to 5 recent microbes as candidates for predators. - -- Gives something semi random - self.preyCandidates[self.currentPreyIndex] = microbeEntity - self.preyEntityToIndexMap[entityId] = self.currentPreyIndex - self.currentPreyIndex = (self.currentPreyIndex)%6 - - end - - --for removing cell from table when it is removed from the world - for _, entityId in pairs(self.microbeEntities:removedEntities()) do - microbes_number[entityId] = nil - end - - --for counting all the cells in the world and get it's entity - for _, entityId in pairs(self.microbeEntities:addedEntities()) do - local microbeEntity = Entity.new(entityId, self.gameState.wrapper) - microbes_number[entityId] = microbeEntity - end - - -- Does this actually do something? - for _, entityId in pairs(self.emitters:removedEntities()) do - self.oxygenEmitters[entityId] = nil - self.glucoseEmitters[entityId] = nil - end - - for _, entityId in pairs(self.emitters:addedEntities()) do - local emitterComponent = getComponent(entityId, self.gameState, CompoundEmitterComponent) - if emitterComponent ~= nil then --for making sure the emmitterComponent get set before - if emitterComponent.compoundId == CompoundRegistry.getCompoundId("oxygen") then - self.oxygenEmitters[entityId] = true - elseif emitterComponent.compoundId == CompoundRegistry.getCompoundId("glucose") then - self.glucoseEmitters[entityId] = true - end - end - end - self.emitters:clearChanges() - self.entities:clearChanges() - self.microbeEntities:clearChanges() - for _, microbeEntity in pairs(self.microbes) do - local aiComponent = getComponent(microbeEntity, MicrobeAIControllerComponent) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local sceneNodeComponent = getComponent(microbeEntity, OgreSceneNodeComponent) - - aiComponent.intervalRemaining = aiComponent.intervalRemaining + logicTime - while aiComponent.intervalRemaining > aiComponent.reevalutationInterval do - aiComponent.intervalRemaining = aiComponent.intervalRemaining - aiComponent.reevalutationInterval - - local compoundId = CompoundRegistry.getCompoundId("oxytoxy") - local targetPosition = nil - local numberOfAgentVacuoless = microbeComponent.specialStorageOrganelles[compoundId] - - --for getting the prey - for m_microbeEntityId, m_microbeEntity in pairs (microbes_number) do - local m_microbeComponent = getComponent(m_microbeEntity, MicrobeComponent) - local m_sceneNodeComponent = getComponent(m_microbeEntity, OgreSceneNodeComponent) - - if self.preys ~= nil then - local v = (m_sceneNodeComponent.transform.position - sceneNodeComponent.transform.position) - if v:length() < 25 and v:length() ~= 0 then - if microbeComponent.maxHitpoints > 1.5 * m_microbeComponent.maxHitpoints then - self.preys[m_microbeEntityId] = m_microbeEntity - end - if numberOfAgentVacuoles ~= nil and numberOfAgentVacuoles ~= 0 - and (m_microbeComponent.specialStorageOrganelles[compoundId] == nil - or m_microbeComponent.specialStorageOrganelles[compoundId] == 0) - and self.preys[m_microbeEntityId] == nil then - - self.preys[m_microbeEntityId] = m_microbeEntity - end - elseif v:length() > 25 or v:length() == 0 then - self.preys[m_microbeEntityId] = nil - end - if self.preys[m_microbeEntityId] ~= nil then - preyMicrobeComponent = getComponent(self.preys[m_microbeEntityId], MicrobeComponent) - if preyMicrobeComponent.maxHitpoints <= self.preyMaxHitpoints then - self.preyMaxHitpoints = preyMicrobeComponent.maxHitpoints - self.p = self.preys[m_microbeEntityId] - end - self.preycount = self.preycount + 1 - end - end - end - - --for getting the predator - for predatorEntityId, predatorEntity in pairs (microbes_number) do - local predatorMicrobeComponent = getComponent(predatorEntity, MicrobeComponent) - local predatorSceneNodeComponent = getComponent(predatorEntity, OgreSceneNodeComponent) - - local vec = (predatorSceneNodeComponent.transform.position - sceneNodeComponent.transform.position) - if predatorMicrobeComponent.maxHitpoints > microbeComponent.maxHitpoints * 1.5 and vec:length() < 25 then - self.predators[predatorEntityId] = predatorEntity - end - if (predatorMicrobeComponent.specialStorageOrganelles[compoundId] ~= nil and predatorMicrobeComponent.specialStorageOrganelles[compoundId] ~= 0) - and (numberOfAgentVacuoles == nil or numberOfAgentVacuoles == 0) and vec:length() < 25 then - self.predators[predatorEntityId] = predatorEntity - end - if vec:length() > 25 then - self.predators[predatorEntityId] = nil - end - self.predator = self.predators[predatorEntityId] - end - - if (numberOfAgentVacuoles ~= nil and numberOfAgentVacuoles ~= 0) or microbeComponent.maxHitpoints > 100 then - self.preyCandidates[6] = Entity.new(PLAYER_NAME, self.gameState.wrapper) - self.preyEntityToIndexMap[Entity.new(PLAYER_NAME, self.gameState.wrapper).id] = 6 - local attempts = 0 - while (aiComponent.prey == nil or not aiComponent.prey:exists() - or getComponent( aiComponent.prey, MicrobeComponent) == nil - or getComponent( aiComponent.prey, MicrobeComponent).dead - or (getComponent(aiComponent.prey, MicrobeComponent).speciesName == microbeComponent.speciesName) - or self.preyEntityToIndexMap[aiComponent.prey.id] == nil or self.preyEscaped == true) - and attempts < 6 and self.preycount > 10 do - - aiComponent.prey = self.p --setting the prey - attempts = attempts + 1 - self.preyEscaped = false - end - - if self.predator ~= nil then -- for running away from the predadtor - local predatorSceneNodeComponent = getComponent(self.predator, OgreSceneNodeComponent) - microbeComponent.facingTargetPoint = Vector3(-predatorSceneNodeComponent.transform.position.x, -predatorSceneNodeComponent.transform.position.y, 0) - microbeComponent.movementDirection = Vector3(0, AI_MOVEMENT_SPEED, 0) - end - - if attempts < 6 and aiComponent.prey ~= nil and self.predator == nil then --making sure it is not a prey for someone before start hunting - local preyMicrobeComponent = getComponent(aiComponent.prey, MicrobeComponent) - local preySceneNodeComponent = getComponent(aiComponent.prey, OgreSceneNodeComponent) - - vec = (preySceneNodeComponent.transform.position - sceneNodeComponent.transform.position) - if vec:length() > 25 then - self.preyEscaped = true - end - if vec:length() < 25 and vec:length() > 10 - and MicrobeSystem.getCompoundAmount(microbeEntity, compoundId) > MINIMUM_AGENT_EMISSION_AMOUNT - and microbeComponent.microbetargetdirection < 10 then - MicrobeSystem.emitAgent(microbeEntity, CompoundRegistry.getCompoundId("oxytoxy"), 1) - elseif vec:length() < 10 - and microbeComponent.maxHitpoints > ENGULF_HP_RATIO_REQ * preyMicrobeComponent.maxHitpoints - and not microbeComponent.engulfMode then - MicrobeSystem.toggleEngulfMode(microbeEntity) - elseif vec:length() > 15 and microbeComponent.engulfMode then - MicrobeSystem.toggleEngulfMode(microbeEntity) - end - - vec:normalise() - aiComponent.direction = vec - microbeComponent.facingTargetPoint = Vector3(preySceneNodeComponent.transform.position.x, preySceneNodeComponent.transform.position.y, 0) - microbeComponent.movementDirection = Vector3(0, AI_MOVEMENT_SPEED, 0) - end - else - if MicrobeSystem.getCompoundAmount(microbeEntity, CompoundRegistry.getCompoundId("oxygen")) <= OXYGEN_SEARCH_THRESHHOLD then - -- If we are NOT currenty heading towards an emitter - if aiComponent.targetEmitterPosition == nil or aiComponent.searchedCompoundId ~= CompoundRegistry.getCompoundId("oxygen") then - aiComponent.searchedCompoundId = CompoundRegistry.getCompoundId("oxygen") - local emitterArrayList = {} - local i = 0 - for emitterId, _ in pairs(self.oxygenEmitters) do - i = i + 1 - emitterArrayList[i] = emitterId - end - if i ~= 0 then - local emitterEntity = Entity.new( - emitterArrayList[rng:getInt(1, i)], self.gameState.wrapper) - - aiComponent.targetEmitterPosition = getComponent( - emitterEntity, OgreSceneNodeComponent).transform.position - end - end - targetPosition = aiComponent.targetEmitterPosition - if aiComponent.targetEmitterPosition ~= nil and aiComponent.targetEmitterPosition.z ~= 0 then - aiComponent.targetEmitterPosition = nil - end - elseif MicrobeSystem.getCompoundAmount(microbeEntity, CompoundRegistry.getCompoundId("glucose")) <= GLUCOSE_SEARCH_THRESHHOLD then - -- If we are NOT currenty heading towards an emitter - if aiComponent.targetEmitterPosition == nil or aiComponent.searchedCompoundId ~= CompoundRegistry.getCompoundId("glucose") then - aiComponent.searchedCompoundId = CompoundRegistry.getCompoundId("glucose") - local emitterArrayList = {} - local i = 0 - for emitterId, _ in pairs(self.glucoseEmitters) do - i = i + 1 - emitterArrayList[i] = emitterId - end - if i ~= 0 then - - local emitterEntity = Entity.new( - emitterArrayList[rng:getInt(1, i)], self.gameState.wrapper) - - aiComponent.targetEmitterPosition = getComponent( - emitterEntity, OgreSceneNodeComponent).transform.position - end - end - targetPosition = aiComponent.targetEmitterPosition - - if aiComponent.targetEmitterPosition ~= nil and aiComponent.targetEmitterPosition.z ~= 0 then - aiComponent.targetEmitterPosition = nil - end - else - aiComponent.targetEmitterPosition = nil - end - if aiComponent.targetEmitterPosition == nil then - local randAngle = rng:getReal(0, 2*math.pi) - local randDist = rng:getInt(10, aiComponent.movementRadius) - targetPosition = Vector3(math.cos(randAngle)* randDist, - math.sin(randAngle)* randDist, 0) - end - local vec = (targetPosition - sceneNodeComponent.transform.position) - vec:normalise() - aiComponent.direction = vec - microbeComponent.facingTargetPoint = targetPosition - microbeComponent.movementDirection = Vector3(0,AI_MOVEMENT_SPEED,0) - end - end - end -end diff --git a/scripts/microbe_stage/microbe_control.lua b/scripts/microbe_stage/microbe_control.lua deleted file mode 100644 index 34106c7ab65..00000000000 --- a/scripts/microbe_stage/microbe_control.lua +++ /dev/null @@ -1,56 +0,0 @@ --- System for processing player input in the microbe stage -MicrobeControlSystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - - end -) - -function MicrobeControlSystem:init(gameState) - LuaSystem.init(self, "MicrobeControlSystem", gameState) -end - --- Computes the point the mouse cursor is at -local function getTargetPoint() - local mousePosition = Engine.mouse:normalizedPosition() - local playerCam = Entity.new(CAMERA_NAME, g_luaEngine.currentGameState.wrapper) - local cameraComponent = getComponent(playerCam, OgreCameraComponent) - local ray = cameraComponent:getCameraToViewportRay(mousePosition.x, mousePosition.y) - local plane = Plane.new(Vector3(0, 0, 1), 0) - local intersects, t = ray:intersects(plane) - return ray:getPoint(t) -end - - --- Sums up the directional input from the keyboard -local function getMovementDirection() - local direction = Vector3(0, 0, 0) - if (Engine.keyboard:isKeyDown(KEYCODE.KC_W)) then - direction = direction + Vector3(0, 1, 0) - end - if (Engine.keyboard:isKeyDown(KEYCODE.KC_S)) then - direction = direction + Vector3(0, -1, 0) - end - if (Engine.keyboard:isKeyDown(KEYCODE.KC_A)) then - direction = direction + Vector3(-1, 0, 0) - end - if (Engine.keyboard:isKeyDown(KEYCODE.KC_D)) then - direction = direction + Vector3(1, 0, 0) - end - direction:normalise() - return direction -end - - -function MicrobeControlSystem:update(renderTime, logicTime) - local player = Entity.new("player", self.gameState.wrapper) - local microbe = getComponent(player, MicrobeComponent) - if microbe and not microbe.dead then - local targetPoint = getTargetPoint() - local movementDirection = getMovementDirection() - microbe.facingTargetPoint = getTargetPoint() - microbe.movementDirection = movementDirection - end -end diff --git a/scripts/microbe_stage/microbe_operations.as b/scripts/microbe_stage/microbe_operations.as new file mode 100644 index 00000000000..2dba5aef2fe --- /dev/null +++ b/scripts/microbe_stage/microbe_operations.as @@ -0,0 +1,1079 @@ +// Operations on microbe entities +#include "biome.as" +#include "species_system.as" + +namespace MicrobeOperations{ + +// Queries the currently stored amount of an compound +// +// @param compoundId +// The id of the compound to query +// +// @returns amount +// The amount stored in the microbe's storage oraganelles +double getCompoundAmount(CellStageWorld@ world, ObjectID microbeEntity, CompoundId compoundId){ + return world.GetComponent_CompoundBagComponent(microbeEntity). + getCompoundAmount(compoundId); +} + +// Getter for microbe species +// +// returns the species component or null if it doesn't have a valid species +SpeciesComponent@ getSpeciesComponent(CellStageWorld@ world, ObjectID microbeEntity){ + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + // This needs to loop all the components and get the matching one + auto entity = findSpeciesEntityByName(world, microbeComponent.speciesName); + + return world.GetComponent_SpeciesComponent(entity); +} + +// Getter for microbe species +// +// returns the species component or null if species with that name doesn't exist +SpeciesComponent@ getSpeciesComponent(CellStageWorld@ world, const string &in speciesName){ + + // This needs to loop all the components and get the matching one + auto entity = findSpeciesEntityByName(world, speciesName); + + return world.GetComponent_SpeciesComponent(entity); +} + +// Getter for species processor component +// +// returns the processor component or null if such species doesn't have that component +// TODO: check what calls this and make it store the species entity id if it also calls +// getSpeciesComponent to save searching the whole species component index multiple times +ProcessorComponent@ getProcessorComponent(CellStageWorld@ world, const string &in speciesName){ + + // This needs to loop all the components and get the matching one + auto entity = findSpeciesEntityByName(world, speciesName); + + return world.GetComponent_ProcessorComponent(entity); +} + +// Retrieves the organelle occupying a hex cell +// +// @param q, r +// Axial coordinates, relative to the microbe's center +// +// @returns organelle +// The organelle at (q,r) or null if the hex is unoccupied +PlacedOrganelle@ getOrganelleAt(CellStageWorld@ world, ObjectID microbeEntity, Int2 hex){ + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + auto organelle = microbeComponent.organelles[i]; + + auto localQ = hex.X - organelle.q; + auto localR = hex.Y - organelle.r; + if(organelle.organelle.getHex(localQ, localR) !is null){ + return organelle; + } + } + + return null; +} + +// Removes the organelle at a hex cell +// Note that this renders the organelle unusable as we destroy its underlying entity +// +// @param q, r +// Axial coordinates of the organelle's center +// +// @returns success +// True if an organelle has been removed, false if there was no organelle +// at (q,r) +// @note use a more specific version (for example damaged) if available +// +// This is responsible for updating the mass of the cell's physics body +bool removeOrganelle(CellStageWorld@ world, ObjectID microbeEntity, Int2 hex){ + + auto organelle = getOrganelleAt(world, microbeEntity, hex); + if(organelle is null){ + return false; + } + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto rigidBodyComponent = world.GetComponent_Physics(microbeEntity); + + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + + if(microbeComponent.organelles[i] is organelle){ + + microbeComponent.organelles.removeAt(i); + break; + } + } + + auto position = world.GetComponent_Position(microbeEntity); + + organelle.onRemovedFromMicrobe(microbeEntity, rigidBodyComponent.Collision); + + // Need to recreate the body + if(rigidBodyComponent.Body !is null){ + + LOG_INFO("Recreating physics body in removeOrganelle"); + rigidBodyComponent.CreatePhysicsBody(world.GetPhysicalWorld(), + world.GetPhysicalMaterial("cell")); + rigidBodyComponent.SetMass(rigidBodyComponent.Mass - organelle.organelle.mass); + _applyMicrobePhysicsBodySettings(world, rigidBodyComponent); + + // And jump it to the current position + rigidBodyComponent.JumpTo(position); + } + + // This refreshing these things could probably be somewhere else... + calculateHealthFromOrganelles(world, microbeEntity); + microbeComponent.maxBandwidth = microbeComponent.maxBandwidth - + BANDWIDTH_PER_ORGANELLE ; // Temporary solution for decreasing max bandwidth + + microbeComponent.remainingBandwidth = microbeComponent.maxBandwidth; + + return true; +} + +bool organelleDestroyedByDamage(CellStageWorld@ world, ObjectID microbeEntity, Int2 hex){ + + // TODO: effects for destruction? + return removeOrganelle(world, microbeEntity, hex); +} + +// ------------------------------------ // +void respawnPlayer(CellStageWorld@ world){ + + auto playerEntity = GetThriveGame().playerData().activeCreature(); + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(playerEntity)); + auto rigidBodyComponent = world.GetComponent_Physics(playerEntity); + auto sceneNodeComponent = world.GetComponent_RenderNode(playerEntity); + + microbeComponent.dead = false; + microbeComponent.deathTimer = 0; + + // Reset the growth bins of the organelles to full health. + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + microbeComponent.organelles[i].reset(); + } + calculateHealthFromOrganelles(world, playerEntity); + + // Reset position // + rigidBodyComponent.SetPosition(Float3(0, 0, 0), Float4::IdentityQuaternion); + + // The physics body will set the Position on next tick + + // TODO: reset velocity like in the old lua code? + + // This set position is actually useless, but it was in the old lua code + // sceneNodeComponent.Node.setPosition(Float3(0, 0, 0)); + sceneNodeComponent.Hidden = false; + sceneNodeComponent.Marked = true; + + // TODO: give the microbe the values from some table instead. + // The player should actually be also given the value from the STARTED_MICROBES so + // verify that and remove this + storeCompound(world, playerEntity, + SimulationParameters::compoundRegistry().getTypeId("atp"), 50, false); + + setRandomBiome(world); + cast(world.GetScriptSystem("MicrobeStageHudSystem")). + suicideButtonreset(); +} + + +// Attempts to obtain an amount of bandwidth for immediate use. +// This should be in conjunction with most operations ejecting or absorbing compounds +// and agents for microbe. +// +// @param maicrobeEntity +// The entity of the microbe to get the bandwidth from. +// +// @param maxAmount +// The max amount of units that is requested. +// +// @param compoundId +// The compound being requested for volume considerations. +// +// @return +// amount in units avaliable for use. +float getBandwidth(CellStageWorld@ world, ObjectID microbeEntity, float maxAmount, + CompoundId compoundId +) { + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + auto compoundVolume = SimulationParameters::compoundRegistry().getTypeData( + compoundId).volume; + + auto amount = min(maxAmount * compoundVolume, microbeComponent.remainingBandwidth); + microbeComponent.remainingBandwidth = microbeComponent.remainingBandwidth - amount; + return amount / compoundVolume; +} + +// Stores an compound in the microbe's storage organelles +// +// @param compoundId +// The compound to store +// +// @param amount +// The amount to store +// +// @param bandwidthLimited +// Determines if the storage operation is to be limited by the bandwidth of the microbe +// +// @returns leftover +// The amount of compound not stored, due to bandwidth or being full +float storeCompound(CellStageWorld@ world, ObjectID microbeEntity, CompoundId compoundId, + double amount, bool bandwidthLimited) +{ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto storedAmount = amount; + + if(bandwidthLimited){ + storedAmount = getBandwidth(world, microbeEntity, amount, compoundId); + } + + storedAmount = min(storedAmount, + microbeComponent.capacity - microbeComponent.stored); + + world.GetComponent_CompoundBagComponent(microbeEntity).giveCompound(compoundId, + storedAmount); + + microbeComponent.stored = microbeComponent.stored + storedAmount; + return amount - storedAmount; +} + +// Removes compounds from the microbe's storage organelles +// +// @param compoundId +// The compound to remove +// +// @param maxAmount +// The maximum amount to take +// +// @returns amount +// The amount that was actually taken, between 0.0 and maxAmount. +double takeCompound(CellStageWorld@ world, ObjectID microbeEntity, CompoundId compoundId, + double maxAmount) +{ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto takenAmount = world.GetComponent_CompoundBagComponent(microbeEntity). + takeCompound(compoundId, maxAmount); + + microbeComponent.stored = microbeComponent.stored - takenAmount; + return takenAmount; +} + +// Ejects compounds from the microbes behind position, into the enviroment +// Note that the compounds ejected are created in this world and not taken from the microbe +// +// @param compoundId +// The compound type to create and eject +// +// @param amount +// The amount to eject +void ejectCompound(CellStageWorld@ world, ObjectID microbeEntity, CompoundId compoundId, + double amount) +{ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto membraneComponent = world.GetComponent_MembraneComponent(microbeEntity); + auto position = world.GetComponent_Position(microbeEntity); + + // The back of the microbe + Float3 exit = Hex::axialToCartesian(0, 1); + auto membraneCoords = membraneComponent.GetExternalOrganelle(exit.X, exit.Z); + + //Get the distance to eject the compunds + auto maxR = 0; + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + auto organelle = microbeComponent.organelles[i]; + auto hexes = organelle.organelle.getHexes(); + for(uint a = 0; a < hexes.length(); ++a){ + auto hex = hexes[a]; + if(hex.r + organelle.r > maxR){ + maxR = hex.r + organelle.r; + } + } + } + + //The distance is two hexes away from the back of the microbe. + //This distance could be precalculated when adding/removing an organelle + //for more efficient pooping. + auto ejectionDistance = (maxR + 3) * HEX_SIZE; + + auto angle = 180; + // Find the direction the microbe is facing + auto yAxis = Ogre::Quaternion(position._Orientation).yAxis(); + auto microbeAngle = atan2(yAxis.x, yAxis.y); + if(microbeAngle < 0){ + microbeAngle = microbeAngle + 2 * PI; + } + microbeAngle = microbeAngle * 180 / PI; + // Take the microbe angle into account so we get world relative degrees + auto finalAngle = (angle + microbeAngle) % 360; + + auto s = sin(finalAngle/180*PI); + auto c = cos(finalAngle/180*PI); + + auto xnew = -membraneCoords.x * c + membraneCoords.y * s; + auto ynew = membraneCoords.x * s + membraneCoords.y * c; + + auto amountToEject = takeCompound(world, microbeEntity, compoundId, + amount/10.0); + createCompoundCloud(world, compoundId, + position._Position.X + xnew * ejectionDistance, + position._Position.Y + ynew * ejectionDistance, + // TODO: Why is this multiplied by 5000? + // And why amountToEject is ignored + amount * 5000); +} + +void purgeCompounds(CellStageWorld@ world, ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto compoundBag = world.GetComponent_CompoundBagComponent(microbeEntity); + + // // Uncomment to print compound economic information to the console. + // if(microbeComponent.isPlayerMicrobe){ + // for(compound, _ in pairs(compoundTable)){ + // compoundId = CompoundRegistry.getCompoundId(compound); + // print(compound, compoundBag.getPrice(compoundId), + // compoundBag.getDemand(compoundId)); + // } + // } + // print(""); + + // TODO: all the calls here to compound amounts and dumping + // re-retrieve the microbe component This is pretty slow! This is + // why all of these methods need to be able to use already + // retrieved components + + // Dumping all the useless compounds (with price = 0). + uint64 compoundCount = SimulationParameters::compoundRegistry().getSize(); + for(uint compoundId = 0; compoundId < compoundCount; ++compoundId){ + + auto price = compoundBag.getPrice(compoundId); + if(price <= 0){ + auto amountToEject = getCompoundAmount(world, microbeEntity, compoundId); + // TODO: make sure that this does the right thing. As the + // lua version used 'amount' here which is not declared + // and can't be over 0 so this wasn't ever executed. + if(amountToEject > 0){ + amountToEject = takeCompound(world, microbeEntity, compoundId, amountToEject); + + ejectCompound(world, microbeEntity, compoundId, amountToEject); + } + } + } + + // Perhaps we need to also dump usefull stuff + // TODO: make sure that ejecting updates this otherwise we might dump usefull compounds + // even if we shouldn't + auto compoundAmountToDump = microbeComponent.stored - microbeComponent.capacity; + + if(compoundAmountToDump > 0){ + //Calculating each compound price to dump proportionally. + dictionary compoundPrices = {}; + float priceSum = 0; + for(uint compoundId = 0; compoundId < compoundCount; ++compoundId){ + auto amount = getCompoundAmount(world, microbeEntity, compoundId); + + if(amount > 0){ + auto price = compoundBag.getPrice(compoundId); + compoundPrices[formatInt(compoundId)] = price; + priceSum += amount / price; + } + } + + //Dumping each compound according to it's price. + for(uint compoundId = 0; compoundId < compoundCount; ++compoundId){ + + auto price = float(compoundPrices[formatInt(compoundId)]); + + // And again this get amount retrieves components that we already have! + auto amountToEject = compoundAmountToDump * (getCompoundAmount(world, + microbeEntity, compoundId) / price) / priceSum; + + // This was also 'amount' so maybe this didn't work either? + if(amountToEject > 0){ + amountToEject = takeCompound(world, microbeEntity, + compoundId, amountToEject); + + ejectCompound(world, microbeEntity, compoundId, amountToEject); + } + } + } +} + + +void calculateHealthFromOrganelles(CellStageWorld@ world, ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + microbeComponent.hitpoints = 0; + microbeComponent.maxHitpoints = 0; + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + auto organelle = microbeComponent.organelles[i]; + + if(organelle.getCompoundBin() < 1.0){ + microbeComponent.hitpoints += round(organelle.getCompoundBin() * + MICROBE_HITPOINTS_PER_ORGANELLE); + } else { + microbeComponent.hitpoints += MICROBE_HITPOINTS_PER_ORGANELLE; + } + + microbeComponent.maxHitpoints += MICROBE_HITPOINTS_PER_ORGANELLE; + } +} + +void flashMembraneColour(CellStageWorld@ world, ObjectID microbeEntity, uint duration, + Float4 colour) +{ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + if(microbeComponent.flashDuration <= 0){ + microbeComponent.flashColour = colour; + microbeComponent.flashDuration = duration; + } +} + +// Applies the default membrane colour +// TODO: this is probably broken (the c++ membrane system doesn't apply this) +void applyMembraneColour(CellStageWorld@ world, ObjectID microbeEntity){ + + auto membraneComponent = world.GetComponent_MembraneComponent(microbeEntity); + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + membraneComponent.setColour(microbeComponent.speciesColour); +} + + +// Disables or enabled engulfmode for a microbe, allowing or +// disallowed it to absorb other microbes +void toggleEngulfMode(CellStageWorld@ world, ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + // auto soundSourceComponent = world.GetComponent_SoundSourceComponent(microbeEntity); + + if(microbeComponent.engulfMode){ + microbeComponent.movementFactor = microbeComponent.movementFactor * + ENGULFING_MOVEMENT_DIVISION; + // soundSourceComponent.stopSound("microbe-engulfment"); // Possibly comment out. + } else { + microbeComponent.movementFactor = microbeComponent.movementFactor / + ENGULFING_MOVEMENT_DIVISION; + } + + microbeComponent.engulfMode = !microbeComponent.engulfMode; +} + + +// Damages the microbe, killing it if its hitpoints drop low enough +// +// @param amount +// amount of hitpoints to substract +void damage(CellStageWorld@ world, ObjectID microbeEntity, uint amount, const string &in + damageType) +{ + if(damageType == ""){ + assert(false, "Damage type is empty"); + } + + if(amount < 0){ + assert(false, "Can't deal negative damage. Use MicrobeOperations::heal instead"); + } + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + // auto soundSourceComponent = world.GetComponent_SoundSourceComponent(microbeEntity); + + if(damageType == "toxin"){ + //play the toxin sound + GetEngine().GetSoundDevice().Play2DSoundEffect("Data/Sound/soundeffects/microbe-toxin-damage.ogg"); + } + + // Choose a random organelle or membrane to damage. + // TODO: CHANGE TO USE AGENT CODES FOR DAMAGE. + int rand = GetEngine().GetRandom().GetNumber(0, int(microbeComponent.maxHitpoints / + MICROBE_HITPOINTS_PER_ORGANELLE) - 1); + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + // If this is the organelle we have chosen... + if(int(i) == rand){ + // Deplete its health/compoundBin. + microbeComponent.organelles[i].damageOrganelle(amount); + break; + } + } + + // Find out the amount of health the microbe has. + // TODO: this could also be more efficient if we calculate above the amount of + // total health lost and update the health directly + calculateHealthFromOrganelles(world, microbeEntity); + + if(microbeComponent.hitpoints <= 0){ + microbeComponent.hitpoints = 0; + kill(world, microbeEntity); + } +} + + +// TODO: we have a similar method in procedural_microbes.lua and another one +// in microbe_editor.lua. +// They probably should all use the same one. +// We'll probably need a rotation for this, although maybe it should be done in c++ where +// sets are a thing? +bool validPlacement(CellStageWorld@ world, ObjectID microbeEntity, const Organelle@ organelle, + Int2 posToCheck +) { + auto touching = false; + assert(false, "TODO: should this hex list here be rotated, this doesn't seem to take " + "a rotation parameter in"); + auto hexes = organelle.getHexes(); + for(uint i = 0; i < hexes.length(); ++i){ + + auto hex = hexes[i]; + + auto existingOrganelle = getOrganelleAt(world, microbeEntity, {hex.q + posToCheck.X, + hex.r + posToCheck.Y}); + if(existingOrganelle !is null){ + if(existingOrganelle.organelle.name != "cytoplasm"){ + return false ; + } + } + + // These are pretty expensive methods + if(getOrganelleAt(world, microbeEntity, {hex.q + posToCheck.X + 0, + hex.r + posToCheck.Y - 1}) !is null || + getOrganelleAt(world, microbeEntity, {hex.q + posToCheck.X + 1, + hex.r + posToCheck.Y - 1}) !is null || + getOrganelleAt(world, microbeEntity, {hex.q + posToCheck.X + 1, + hex.r + posToCheck.Y + 0}) !is null || + getOrganelleAt(world, microbeEntity, {hex.q + posToCheck.X + 0, + hex.r + posToCheck.Y + 1}) !is null || + getOrganelleAt(world, microbeEntity, {hex.q + posToCheck.X - 1, + hex.r + posToCheck.Y + 1}) !is null || + getOrganelleAt(world, microbeEntity, {hex.q + posToCheck.X - 1, + hex.r + posToCheck.Y + 0}) !is null) + { + touching = true; + } + } + + return touching; +} + + +// Adds a new organelle +// +// The space at (q,r) must not be occupied by another organelle already. +// +// @param q,r +// Offset of the organelle's center relative to the microbe's center in +// axial coordinates. These are now in the organelle object +// +// @param organelle +// The organelle to add +// +// @return +// returns whether the organelle was added +bool addOrganelle(CellStageWorld@ world, ObjectID microbeEntity, PlacedOrganelle@ organelle) +{ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + // Exact coordinate check // + // This isn't perfect so that's why it needs to have been checked before that this + // place isn't full + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + if(microbeComponent.organelles[i].q == organelle.q && + microbeComponent.organelles[i].r == organelle.r) + { + return false; + } + } + + auto membraneComponent = world.GetComponent_MembraneComponent(microbeEntity); + auto rigidBodyComponent = world.GetComponent_Physics(microbeEntity); + auto position = world.GetComponent_Position(microbeEntity); + + microbeComponent.organelles.insertLast(@organelle); + // Float3 translation = Hex::axialToCartesian(organelle.q, organelle.r); + + // Collision shape + // Need to begin update for our physics body as this adds the + // hexes of the organelle as a sub collision + // This isn't optimal if multiple are added but simplifies calling this + NewtonCollision@ collision = rigidBodyComponent.Collision; + collision.CompoundCollisionBeginAddRemove(); + + organelle.onAddedToMicrobe(microbeEntity, world, collision); + + collision.CompoundCollisionEndAddRemove(); + + // The body is recreated if it existed already + if(rigidBodyComponent.Body !is null){ + + // Need to recreate the body + LOG_INFO("Recreating physics body in addOrganelle"); + rigidBodyComponent.CreatePhysicsBody(world.GetPhysicalWorld(), + world.GetPhysicalMaterial("cell")); + + rigidBodyComponent.SetMass(rigidBodyComponent.Mass + organelle.organelle.mass); + + _applyMicrobePhysicsBodySettings(world, rigidBodyComponent); + + // And jump it to the current position + rigidBodyComponent.JumpTo(position); + } + + calculateHealthFromOrganelles(world, microbeEntity); + microbeComponent.maxBandwidth = microbeComponent.maxBandwidth + + BANDWIDTH_PER_ORGANELLE; // Temporary solution for increasing max bandwidth + microbeComponent.remainingBandwidth = microbeComponent.maxBandwidth; + + // Send the organelles to the membraneComponent so that the membrane can "grow" + // This is always 0? + auto localQ = organelle.q - organelle.q; + auto localR = organelle.r - organelle.r; + + // I guess this might skip sending organelles that have no hexes? to the membrane + if(organelle.organelle.getHex(localQ, localR) !is null){ + + auto hexes = organelle.organelle.getHexes(); + for(uint i = 0; i < hexes.length(); ++i){ + + auto hex = hexes[i]; + + auto q = hex.q + organelle.q; + auto r = hex.r + organelle.r; + Float3 membranePoint = Hex::axialToCartesian(q, r); + // TODO: this is added here to make it impossible for our + // caller to forget to call this, and this basically only + // once does something and then on next tick the membrane + // is initialized again + membraneComponent.clear(); + membraneComponent.sendOrganelles(membranePoint.X, membranePoint.Z); + } + + // What is this return? + // return organelle; + return true; + } + + return true; +} + + +// speciesName decides the template to use, while individualName is +// used for referencing the instance +ObjectID spawnMicrobe(CellStageWorld@ world, Float3 pos, const string &in speciesName, + bool aiControlled, const string &in individualName +) { + assert(world !is null); + assert(speciesName != ""); + + if(pos.Y != 0) + LOG_WARNING("spawnMicrobe: spawning at y-coordinate: " + pos.Y); + + auto processor = getProcessorComponent(world, speciesName); + + if(processor is null){ + + LOG_ERROR("Skipping microbe spawn because species '" + speciesName + + "' doesn't have a processor component"); + + return NULL_OBJECT; + } + + auto microbeEntity = _createMicrobeEntity(world, individualName, aiControlled, speciesName, + // in_editor + false); + + // Teleport the cell to the right position + auto microbePos = world.GetComponent_Position(microbeEntity); + microbePos._Position = pos; + microbePos.Marked = true; + + auto physics = world.GetComponent_Physics(microbeEntity); + physics.JumpTo(microbePos); + + // Try setting the position immediately as well (as otherwise it + // takes until the next tick for this to take effect) + auto node = world.GetComponent_RenderNode(microbeEntity); + node.Node.setPosition(pos); + + auto speciesEntity = findSpeciesEntityByName(world, speciesName); + auto species = world.GetComponent_SpeciesComponent(speciesEntity); + + //bacteria get scaled to half size + if(species.isBacteria){ + node.Scale = Float3(0.5, 0.5, 0.5); + node.Marked = true; + } + + return microbeEntity; +} + +ObjectID spawnBacteria(CellStageWorld@ world, Float3 pos, const string &in speciesName, + bool aiControlled, const string &in individualName, bool partOfColony +) { + assert(world !is null); + assert(speciesName != ""); + + if(pos.Y != 0) + LOG_WARNING("spawnBacteria: spawning at y-coordinate: " + pos.Y); + + auto processor = getProcessorComponent(world, speciesName); + + if(processor is null){ + + LOG_ERROR("Skipping microbe spawn because species '" + speciesName + + "' doesn't have a processor component"); + + return NULL_OBJECT; + } + + auto microbeEntity = _createMicrobeEntity(world, individualName, aiControlled, speciesName, + // in_editor + false); + + // Teleport the cell to the right position + auto microbePos = world.GetComponent_Position(microbeEntity); + microbePos._Position = pos; + microbePos.Marked = true; + + auto physics = world.GetComponent_Physics(microbeEntity); + physics.JumpTo(microbePos); + + // Try setting the position immediately as well (as otherwise it + // takes until the next tick for this to take effect) + auto node = world.GetComponent_RenderNode(microbeEntity); + node.Node.setPosition(pos); + + auto speciesEntity = findSpeciesEntityByName(world, speciesName); + auto species = world.GetComponent_SpeciesComponent(speciesEntity); + + //bacteria get scaled to half size + node.Scale = Float3(0.5, 0.5, 0.5); + node.Marked = true; + //need to set bacteria spawn and it needs to be squared like it is in the spawn system. code, if part of colony but not directly spawned give a spawned component + if (partOfColony) + { + world.Create_SpawnedComponent(microbeEntity,BACTERIA_SPAWN_RADIUS*BACTERIA_SPAWN_RADIUS); + } + //stuff + LOG_WARNING("spawning bacterium radius "+ BACTERIA_SPAWN_RADIUS); + return microbeEntity; +} +// Creates a new microbe with all required components. Use spawnMicrobe from other +// code instead of this function +// +// @param name +// The entity's name. If null, the entity will be unnamed. +// +// @returns microbe +// An object of type Microbe +ObjectID _createMicrobeEntity(CellStageWorld@ world, const string &in name, bool aiControlled, + const string &in speciesName, bool in_editor) +{ + assert(speciesName != "", "Empty species name for create microbe"); + + auto speciesEntity = findSpeciesEntityByName(world, speciesName); + auto species = world.GetComponent_SpeciesComponent(speciesEntity); + + if(speciesEntity == NULL_OBJECT) + assert(false, "Trying to create a microbe with invalid species"); + + ObjectID entity = world.CreateEntity(); + + auto position = world.Create_Position(entity, Float3(0, 0, 0), Float4::IdentityQuaternion); + + auto rigidBody = world.Create_Physics(entity, world, position, null); + auto collision = world.GetPhysicalWorld().CreateCompoundCollision(); + + rigidBody.SetCollision(collision); + + auto membraneComponent = world.Create_MembraneComponent(entity); + + // auto soundComponent = SoundSourceComponent(); + // auto s1 = null; + // soundComponent.addSound("microbe-release-toxin", + // "soundeffects/microbe-release-toxin.ogg"); + // soundComponent.addSound("microbe-toxin-damage", + // "soundeffects/microbe-toxin-damage.ogg"); + // soundComponent.addSound("microbe-death", "soundeffects/microbe-death.ogg"); + // soundComponent.addSound("microbe-pickup-organelle", + // "soundeffects/microbe-pickup-organelle.ogg"); + // soundComponent.addSound("microbe-engulfment", "soundeffects/engulfment.ogg"); + // soundComponent.addSound("microbe-reproduction", "soundeffects/reproduction.ogg"); + + // s1 = soundComponent.addSound("microbe-movement-1", + // "soundeffects/microbe-movement-1.ogg"); + // s1.properties.volume = 0.4; + // s1.properties.touch(); + // s1 = soundComponent.addSound("microbe-movement-turn", + // "soundeffects/microbe-movement-2.ogg"); + // s1.properties.volume = 0.1; + // s1.properties.touch(); + // s1 = soundComponent.addSound("microbe-movement-2", + // "soundeffects/microbe-movement-3.ogg"); + // s1.properties.volume = 0.4; + // s1.properties.touch(); + + auto compoundAbsorberComponent = world.Create_CompoundAbsorberComponent(entity); + + world.Create_RenderNode(entity); + auto compoundBag = world.Create_CompoundBagComponent(entity); + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Create(entity)); + + microbeComponent.init(entity, not aiControlled, speciesName); + + //dont give them ai if they are a bacteria + if(aiControlled && species.isBacteria==false){ + world.GetScriptComponentHolder("MicrobeAIControllerComponent").Create(entity); + } + + // Rest of the stuff doesn't really work in_editor + // TODO: verify that this is actually the case + if(in_editor){ + + return entity; + } + + auto processor = world.GetComponent_ProcessorComponent(speciesEntity); + + if(processor is null){ + LOG_ERROR("Microbe species '" + microbeComponent.speciesName + + "' doesn't have a processor component"); + // assert(processor !is null); + } else { + + compoundBag.setProcessor(processor, microbeComponent.speciesName); + } + + // Apply the template // + Species::applyTemplate(world, entity, species); + + // ------------------------------------ // + // Initialization logic taken from MicrobeSystem and put here now + assert(microbeComponent.organelles.length() > 0, "Microbe has no " + "organelles in initializeMicrobe"); + + // We create physics body after adding the organelles as that + // requires the physics body to be recreated when any organelle is + // added (if the body already exists at that point) so we do it + // here after that + rigidBody.CreatePhysicsBody(world.GetPhysicalWorld(), world.GetPhysicalMaterial("cell")); + + assert(rigidBody.Body !is null); + + // Allowing the microbe to absorb all the compounds. + setupAbsorberForAllCompounds(compoundAbsorberComponent); + + // We don't add the sub collisions here. Instead they are + // individually added in addOrganelle, which is not very efficient + // rigidBody.Collision.CompoundCollisionBeginAddRemove(); + // rigidBody.Collision.CompoundCollisionEndAddRemove(); + + float mass = 0.f; + + // Organelles + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + + auto organelle = microbeComponent.organelles[i]; + + // organelles are already initialized when they are added + // Not sure if this reset is needed here + organelle.reset(); + + mass += organelle.organelle.mass; + } + + rigidBody.SetMass(mass); + _applyMicrobePhysicsBodySettings(world, rigidBody); + + microbeComponent.initialized = true; + return entity; +} + +void _applyMicrobePhysicsBodySettings(CellStageWorld@ world, Physics@ rigidBody){ + + // TODO: apply all these properties + rigidBody.SetLinearDamping(0.5); + // This is new + rigidBody.SetAngularDamping(0.2); + + // rigidBody.properties.friction = 0.2; + // rigidBody.properties.mass = 0.0; + // rigidBody.properties.linearFactor = Vector3(1, 1, 0); + // rigidBody.properties.angularFactor = Vector3(0, 0, 1); + // rigidBody.properties.touch(); + + // auto reactionHandler = CollisionComponent(); + // reactionHandler.addCollisionGroup("microbe"); + + + // Constraint to 2d movement + if(!rigidBody.CreatePlaneConstraint(world.GetPhysicalWorld(), Float3(0, 1, 0))){ + LOG_ERROR("Failed to constraint cell to 2d plane"); + } +} + +// Kills the microbe, releasing stored compounds into the enviroment +void kill(CellStageWorld@ world, ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto rigidBodyComponent = world.GetComponent_Physics(microbeEntity); + // auto soundSourceComponent = world.GetComponent_SoundSourceComponent(microbeEntity); + auto microbeSceneNode = world.GetComponent_RenderNode(microbeEntity); + auto position = world.GetComponent_Position(microbeEntity); + + // Hacky but meh. + if(microbeComponent.dead){ + LOG_ERROR("Trying to kill a dead microbe"); + return; + } + + // Releasing all the agents. + auto storageTypes = microbeComponent.specialStorageOrganelles.getKeys(); + for(uint i = 0; i < storageTypes.length(); ++i){ + + CompoundId compoundId = parseInt(storageTypes[i]); + + auto _amount = getCompoundAmount(world, microbeEntity, compoundId); + while(_amount > 0){ + // Eject up to 3 units per particle + auto ejectedAmount = takeCompound(world, microbeEntity, compoundId, 3); + + auto direction = Float3(GetEngine().GetRandom().GetNumber(0.0f, 1.0f) * 2 - 1, + 0, GetEngine().GetRandom().GetNumber(0.0f, 1.0f) * 2 - 1); + createAgentCloud(world, compoundId, position._Position, direction, ejectedAmount); + _amount = _amount - ejectedAmount; + } + } + dictionary compoundsToRelease; + // Eject the compounds that was in the microbe + uint64 compoundCount = SimulationParameters::compoundRegistry().getSize(); + for(uint compoundId = 0; compoundId < compoundCount; ++compoundId){ + + auto total = getCompoundAmount(world, microbeEntity, compoundId); + auto ejectedAmount = takeCompound(world, microbeEntity, + compoundId, total); + compoundsToRelease[formatInt(compoundId)] = ejectedAmount; + } + + // Eject some part of the build cost of all the organelles + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + + auto organelle = microbeComponent.organelles[i]; + + auto keys = organelle.organelle.initialComposition.getKeys(); + + for(uint a = 0; a < keys.length(); ++a){ + + float amount = float(organelle.organelle.initialComposition[keys[a]]); + + auto compoundId = SimulationParameters::compoundRegistry().getTypeId(keys[a]); + + auto key = formatInt(compoundId); + + if(!compoundsToRelease.exists(key)){ + compoundsToRelease[key] = amount * COMPOUND_RELEASE_PERCENTAGE; + } else { + compoundsToRelease[key] = float(compoundsToRelease[key]) + + amount * COMPOUND_RELEASE_PERCENTAGE; + } + } + } + + // TODO: make the compounds be released inside of the microbe and not in the back. + auto keys = compoundsToRelease.getKeys(); + for(uint i = 0; i < keys.length(); ++i){ + + ejectCompound(world, microbeEntity, parseInt(keys[i]), + float(compoundsToRelease[keys[i]])); + } + + //play the death sound + GetEngine().GetSoundDevice().Play2DSoundEffect("Data/Sound/soundeffects/microbe-death.ogg"); + + auto deathAnimationEntity = world.CreateEntity(); + auto lifeTimeComponent = world.Create_TimedLifeComponent(deathAnimationEntity, 4000); + auto deathAnimSceneNode = world.Create_RenderNode(deathAnimationEntity); + auto deathAnimModel = world.Create_Model(deathAnimationEntity, deathAnimSceneNode.Node, + "MicrobeDeath.mesh"); + + LOG_WRITE("TODO: play animation deathAnimModel"); + // deathAnimModel.GraphicalObject.playAnimation("Death", false); + + deathAnimSceneNode.Node.setPosition(position._Position); + + + microbeComponent.dead = true; + microbeComponent.deathTimer = 5000; + microbeComponent.movementDirection = Float3(0,0,0); + + rigidBodyComponent.ClearVelocity(); + + if(!microbeComponent.isPlayerMicrobe){ + + // Destroy the physics state // + rigidBodyComponent.Release(); + } + + if(microbeComponent.wasBeingEngulfed){ + removeEngulfedEffect(world, microbeEntity); + } + + microbeSceneNode.Hidden = true; + microbeSceneNode.Marked = true; +} + +void removeEngulfedEffect(CellStageWorld@ world, ObjectID microbeEntity){ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + microbeComponent.movementFactor = microbeComponent.movementFactor * + ENGULFED_MOVEMENT_DIVISION; + microbeComponent.wasBeingEngulfed = false; + + MicrobeComponent@ hostileMicrobeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find( + microbeComponent.hostileEngulfer)); + + if(hostileMicrobeComponent !is null){ + hostileMicrobeComponent.isCurrentlyEngulfing = false; + } + + auto hostileRigidBodyComponent = world.GetComponent_Physics( + microbeComponent.hostileEngulfer); + + // The component is null sometimes, probably due to despawning. + if(hostileRigidBodyComponent !is null){ + //hostileRigidBodyComponent.reenableAllCollisions(); + LOG_WRITE("TODO: redo this thing: " + "hostileRigidBodyComponent.reenableAllCollisions();"); + } + // Causes crash because sound was already stopped. + //microbeComponent.hostileEngulfer.soundSource.stopSound("microbe-engulfment") +} + +// Sets the color of the microbe's membrane. +void setMembraneColour(CellStageWorld@ world, ObjectID microbeEntity, Float4 colour){ + auto membraneComponent = world.GetComponent_MembraneComponent(microbeEntity); + membraneComponent.setColour(colour); +} + +} + diff --git a/scripts/microbe_stage/microbe_stage.levgm b/scripts/microbe_stage/microbe_stage.levgm new file mode 100644 index 00000000000..585552cb2ba --- /dev/null +++ b/scripts/microbe_stage/microbe_stage.levgm @@ -0,0 +1,34 @@ +// The main module that has all of the microbe scripts + +// This isn't used for anything, increase if you want +Version = 1; + + +o GameModule "microbe_stage"{ + t sourcefiles{ + // It is possible for these files to also include more stuff, but maybe it is clearer + // if everything is also listed here + setup.as + configs.as + organelle_table.as + organelle.as + organelle_component.as + microbe_operations.as + microbe.as + species_system.as + procedural_microbes.as + microbe_ai.as + hex.as + biome.as + + microbe_stage_hud.as + + // TODO: move to a new module + ../script_system.as + } + + l properties{ + + ExtraAccess = "FullFileSystem"; + } +} diff --git a/scripts/microbe_stage/microbe_stage_hud.as b/scripts/microbe_stage/microbe_stage_hud.as new file mode 100644 index 00000000000..385352c0879 --- /dev/null +++ b/scripts/microbe_stage/microbe_stage_hud.as @@ -0,0 +1,930 @@ + +// Now in the c++ camera system +// // Camera limits +// CAMERA_MIN_HEIGHT = 20; +// CAMERA_MAX_HEIGHT = 120; +// CAMERA_VERTICAL_SPEED = 0.015; + +bool global_if_already_displayed = false; + +const array AMBIENT_TRACKS = { + "microbe-theme-1", + // This doesn't exist // + /*"microbe-theme-2",*/ "microbe-theme-3", "microbe-theme-4", + "microbe-theme-5", "microbe-theme-6", "microbe-theme-7" +}; + +//! Updates the hud with relevant information from the player cell +class MicrobeStageHudSystem : ScriptSystem{ + + void Init(GameWorld@ world){ + + @this.World = cast(world); + + assert(this.World !is null, "MicrobeStageHudSystem didn't get proper world"); + + + // global_activeMicrobeStageHudSystem = self; // Global reference for event handlers + + // TODO: this is probably supposed to be in the Run method so that once the player + // unlocks the toxin and exits the editor they get this message + // // No clue where this ss variable is defined + // bool ss = false; + // if(not GetThriveGame().playerData().lockedMap().isLocked("Toxin") and + // not ss and not global_if_already_displayed + // ){ + // showMessage("'E' Releases Toxin"); + // global_if_already_displayed = true; + // } + + // Engine.resumeGame(); + // This updates the microbe stage pause menu load button + this.updateLoadButton(); + + this.chloroplastNotificationdisable(); + this.toxinNotificationdisable(); + this.editornotificationdisable(); + + // Store compound ids for lookups in Run + this.atpId = SimulationParameters::compoundRegistry().getTypeId("atp"); + this.atpVolume = SimulationParameters::compoundRegistry().getTypeData( + this.atpId).volume; + + this.oxygenId = SimulationParameters::compoundRegistry().getTypeId("oxygen"); + this.oxygenVolume = SimulationParameters::compoundRegistry().getTypeData( + this.oxygenId).volume; + + this.aminoacidsId = SimulationParameters::compoundRegistry().getTypeId("aminoacids"); + this.aminoacidsVolume = SimulationParameters::compoundRegistry().getTypeData( + this.aminoacidsId).volume; + + this.ammoniaId = SimulationParameters::compoundRegistry().getTypeId("ammonia"); + this.ammoniaVolume = SimulationParameters::compoundRegistry().getTypeData( + this.ammoniaId).volume; + + this.glucoseId = SimulationParameters::compoundRegistry().getTypeId("glucose"); + this.glucoseVolume = SimulationParameters::compoundRegistry().getTypeData( + this.glucoseId).volume; + + this.co2Id = SimulationParameters::compoundRegistry().getTypeId("co2"); + this.co2Volume = SimulationParameters::compoundRegistry().getTypeData( + this.co2Id).volume; + + this.fattyacidsId = SimulationParameters::compoundRegistry().getTypeId("fattyacids"); + this.fattyacidsVolume = SimulationParameters::compoundRegistry().getTypeData( + this.fattyacidsId).volume; + + this.oxytoxyId = SimulationParameters::compoundRegistry().getTypeId("oxytoxy"); + this.oxytoxyVolume = SimulationParameters::compoundRegistry().getTypeData( + this.oxytoxyId).volume; + + } + + void handleAmbientSound() + { + //randomize ambient sounds out of all available sounds + // The isPlaying check will start a new track when the previous ends + if (@ambienceSounds is null || !ambienceSounds.Get().isPlaying()) + { + @ambienceSounds = _playRandomMicrobeAmbience(); + ambienceSounds.Get().play(); + } + + //play ambient track alongside music and loop it (its meant to be played alongside) + if (@ambientTrack is null || !ambientTrack.Get().isPlaying()) + { + @ambientTrack = GetEngine().GetSoundDevice().Play2DSound("Data/Sound/soundeffects/microbe-ambience.ogg", false, true); + ambientTrack.Get().setVolume(0.5); + ambientTrack.Get().play(); + } + } + + void Release(){ + + } + + void Run(){ + + ObjectID player = GetThriveGame().playerData().activeCreature(); + + // Update player stats if there is a cell currently + if(player != NULL_OBJECT){ + + auto bag = World.GetComponent_CompoundBagComponent(player); + MicrobeComponent@ microbeComponent = cast( + World.GetScriptComponentHolder("MicrobeComponent").Find(player)); + + GenericEvent@ event = GenericEvent("PlayerCompoundAmounts"); + NamedVars@ vars = event.GetNamedVars(); + + // Write data + vars.AddValue(ScriptSafeVariableBlock("hitpoints", + int(microbeComponent.hitpoints))); + vars.AddValue(ScriptSafeVariableBlock("hitpointsMax", + int(microbeComponent.maxHitpoints))); + + if(bag is null){ + + LOG_ERROR("Player activeCreature has no compound bag"); + + } else { + + const auto atpAmount = bag.getCompoundAmount(atpId); + const auto maxATP = microbeComponent.capacity / atpVolume; + + const auto oxygenAmount = bag.getCompoundAmount(oxygenId); + const auto maxOxygen = microbeComponent.capacity / oxygenVolume; + + const auto aminoacidsAmount = bag.getCompoundAmount(aminoacidsId); + const auto maxAminoacids = microbeComponent.capacity / aminoacidsVolume; + + const auto ammoniaAmount = bag.getCompoundAmount(ammoniaId); + const auto maxAmmonia = microbeComponent.capacity / ammoniaVolume; + + const auto glucoseAmount = bag.getCompoundAmount(glucoseId); + const auto maxGlucose = microbeComponent.capacity / glucoseVolume; + + const auto co2Amount = bag.getCompoundAmount(co2Id); + const auto maxCo2 = microbeComponent.capacity / co2Volume; + + const auto fattyacidsAmount = bag.getCompoundAmount(fattyacidsId); + const auto maxFattyacids = microbeComponent.capacity / fattyacidsVolume; + + const auto oxytoxyAmount = bag.getCompoundAmount(oxytoxyId); + const auto maxOxytoxy = microbeComponent.capacity / oxytoxyVolume; + + // Write data + vars.AddValue(ScriptSafeVariableBlock("compoundATP", atpAmount)); + vars.AddValue(ScriptSafeVariableBlock("ATPMax", maxATP)); + + vars.AddValue(ScriptSafeVariableBlock("compoundOxygen", oxygenAmount)); + vars.AddValue(ScriptSafeVariableBlock("OxygenMax", maxOxygen)); + + vars.AddValue(ScriptSafeVariableBlock("compoundAminoacids", aminoacidsAmount)); + vars.AddValue(ScriptSafeVariableBlock("AminoacidsMax", maxAminoacids)); + + vars.AddValue(ScriptSafeVariableBlock("compoundAmmonia", ammoniaAmount)); + vars.AddValue(ScriptSafeVariableBlock("AmmoniaMax", maxAmmonia)); + + vars.AddValue(ScriptSafeVariableBlock("compoundGlucose", glucoseAmount)); + vars.AddValue(ScriptSafeVariableBlock("GlucoseMax", maxGlucose)); + + vars.AddValue(ScriptSafeVariableBlock("compoundCo2", co2Amount)); + vars.AddValue(ScriptSafeVariableBlock("Co2Max", maxCo2)); + + vars.AddValue(ScriptSafeVariableBlock("compoundFattyacids", fattyacidsAmount)); + vars.AddValue(ScriptSafeVariableBlock("FattyacidsMax", maxFattyacids)); + + vars.AddValue(ScriptSafeVariableBlock("compoundOxytoxy", oxytoxyAmount)); + vars.AddValue(ScriptSafeVariableBlock("OxytoxyMax", maxOxytoxy)); + } + + // Fire it off so that the GUI scripts will get it and update the GUI state + GetEngine().GetEventHandler().CallEvent(event); + } + + //since this is ran every step this is a good place to do music code + handleAmbientSound(); + } + + // Nodes not used + void Clear(){ + } + + void CreateAndDestroyNodes(){ + } + + //! This stops sound while the cell stage world isn't active + void Suspend(){ + + LOG_INFO("Suspeding microbe stage background sounds"); + + // Pause to allow resuming + if(ambientTrack !is null) + ambientTrack.Get().pause(); + + if(ambienceSounds !is null) + ambienceSounds.Get().pause(); + } + + //! This resumes sound when the cell stage world is active again + void Resume(){ + + LOG_INFO("Resuming microbe stage background sounds"); + + if(ambientTrack !is null) + ambientTrack.Get().play(); + + if(ambienceSounds !is null) + ambienceSounds.Get().play(); + } + + + void updateLoadButton(){ + + if(FileSystem::FileExists("quick.sav")){ + //this.rootGUIWindow.getChild("PauseMenu").getChild("LoadGameButton").enable(); + } else { + //this.rootGUIWindow.getChild("PauseMenu").getChild("LoadGameButton").disable(); + } + } + + void chloroplastNotificationenable(){ + LOG_INFO("TODO: hud"); + // getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent + // ).playSound("microbe-pickup-organelle"); + // this.rootGUIWindow.getChild("chloroplastUnlockNotification").show(); + b1 = true; + // this.rootGUIWindow.getChild("toxinUnlockNotification").hide(); + } + + void chloroplastNotificationdisable(){ + LOG_INFO("TODO: hud"); + //this.rootGUIWindow.getChild("chloroplastUnlockNotification").hide(); + } + + void toxinNotificationenable(){ + LOG_INFO("TODO: hud"); + // getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent + // ).playSound("microbe-pickup-organelle"); + // this.rootGUIWindow.getChild("toxinUnlockNotification").show(); + b2 = true; + //this.rootGUIWindow.getChild("chloroplastUnlockNotification").hide(); + } + + void toxinNotificationdisable(){ + //this.rootGUIWindow.getChild("toxinUnlockNotification").hide(); + } + void editornotificationdisable(){ + //this.rootGUIWindow.getChild("editornotification").hide(); + } + + void showReproductionDialog(){ + // print("Reproduction Dialog called but currently disabled. Is it needed? Note that the editor button has been enabled") + //global_activeMicrobeStageHudSystem.rootGUIWindow.getChild("ReproductionPanel").show() + if(b3 == false){ + // getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent + // ).playSound("microbe-pickup-organelle"); + // this.rootGUIWindow.getChild("editornotification").show(); + b3 = true; + } + // this.editorButton.enable(); + } + + void suicideButtonClicked(){ + // getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); + if(boolean2 == false){ + boolean = true; + } + } + void suicideButtondisable(){ + // this.rootGUIWindow.getChild("SuicideButton").disable(); + } + void suicideButtonreset(){ + boolean2 = false; + } + + private AudioSource@ _playRandomMicrobeAmbience(){ + + AudioSource@ audio = GetEngine().GetSoundDevice().Play2DSound("Data/Sound/" + + AMBIENT_TRACKS[GetEngine().GetRandom().GetNumber(0, + AMBIENT_TRACKS.length() - 1)] + ".ogg", false, true); + + if (audio is null) + { + LOG_ERROR("Failed to create ambience sound source"); + } + + return audio; + } + + private CellStageWorld@ World; + + + int t1 = 0; + int t2 = 0; + int t3 = 0; + bool b1 = false; + bool b2 = false; + bool b3 = false; + //suicideButton setting up + // really creative naming scheme + bool boolean = false; + bool boolean2 = false; + //hints setting up + bool hintsPanelOpned = false; + bool healthHint = false; + bool atpHint = false; + bool glucoseHint = false; + bool ammoniaHint = false; + bool oxygenHint = false; + bool toxinHint = false; + bool chloroplastHint = false; + dictionary activeHints = {}; + int hintN = 0; + int currentHint = 1; + bool HHO = false; + bool AHO = false; + bool GHO = false; + bool AMHO = false; + bool OHO = false; + bool THO = false; + bool CHO = false; + int glucoseNeeded = 0; + int atpNeeded = 0; + int ammoniaNeeded = 0; + int oxygenNeeded = 0; + int chloroplastNeeded = 0; + int toxinNeeded = 0; + + // TODO: rewrite using Leviathan GuiCollection objects + bool helpOpen = false; + bool menuOpen = false; + // Not this one as this isn't really a collection, just a + // toggleable panel with a single button + bool compoundsOpen = true; + + //instantiate our ambient music source + AudioSource@ ambienceSounds; + //plays alongside music + AudioSource@ ambientTrack; + + CompoundId atpId; + float atpVolume; + + CompoundId oxygenId; + float oxygenVolume; + + CompoundId aminoacidsId; + float aminoacidsVolume; + + CompoundId ammoniaId; + float ammoniaVolume; + + CompoundId glucoseId; + float glucoseVolume; + + CompoundId co2Id; + float co2Volume; + + CompoundId fattyacidsId; + float fattyacidsVolume; + + CompoundId oxytoxyId; + float oxytoxyVolume; +} + + +// void HudSystem.update(renderTime, logicTime){ +// // TODO: use the QuickSaveSystem here? is this duplicated functionality? +// auto saveDown = Engine.keyboard.isKeyDown(KEYCODE.KC_F4) +// auto loadDown = Engine.keyboard.isKeyDown(KEYCODE.KC_F10) +// if(saveDown and not this.saveDown){ +// Engine.save("quick.sav") +// } +// if(loadDown and not this.loadDown){ +// Engine.load("quick.sav") +// } +// this.saveDown = saveDown +// this.loadDown = loadDown +// } + + +// void HudSystem.init(gameState){ +// this.rootGUIWindow = gameState.rootGUIWindow(); + +// auto menuButton = this.rootGUIWindow.getChild("MenuButton"); +// auto saveButton = this.rootGUIWindow.getChild("PauseMenu").getChild("QuicksaveButton") ; +// auto loadButton = this.rootGUIWindow.getChild("PauseMenu").getChild("LoadGameButton"); +// auto resumeButton = this.rootGUIWindow.getChild("PauseMenu").getChild("ResumeButton"); +// auto closeHelpButton = this.rootGUIWindow.getChild("PauseMenu").getChild("CloseHelpButton"); +// local chloroplast_unlock_notification = this.rootGUIWindow.getChild("chloroplastUnlockNotification"); +// local toxin_unlock_notification = this.rootGUIWindow.getChild("toxinUnlockNotification"); +// auto nextHint = this.rootGUIWindow.getChild("HintsPanel").getChild("NextHint"); +// auto lastHint = this.rootGUIWindow.getChild("HintsPanel").getChild("LastHint"); +// //auto collapseButton = this.rootGUIWindow.getChild() collapseButtonClicked +// auto hintsButton = this.rootGUIWindow.getChild("HintsButton"); +// auto helpButton = this.rootGUIWindow.getChild("PauseMenu").getChild("HelpButton"); +// auto helpPanel = this.rootGUIWindow.getChild("PauseMenu").getChild("HelpPanel"); +// this.editorButton = this.rootGUIWindow.getChild("EditorButton"); +// auto suicideButton = this.rootGUIWindow.getChild("SuicideButton"); +// //auto returnButton = this.rootGUIWindow.getChild("MenuButton") +// auto compoundButton = this.rootGUIWindow.getChild("CompoundExpandButton"); +// //auto compoundPanel = this.rootGUIWindow.getChild("CompoundsOpen") +// auto quitButton = this.rootGUIWindow.getChild("PauseMenu").getChild("QuitButton"); +// nextHint.registerEventHandler("Clicked", function() this.nextHintButtonClicked()); +// lastHint.registerEventHandler("Clicked", function() this.lastHintButtonClicked()); +// hintsButton.registerEventHandler("Clicked", function() this.hintsButtonClicked()); +// saveButton.registerEventHandler("Clicked", function() this.saveButtonClicked()); +// loadButton.registerEventHandler("Clicked", function() this.loadButtonClicked()); +// menuButton.registerEventHandler("Clicked", function() this.menuButtonClicked()); +// resumeButton.registerEventHandler("Clicked", function() this.resumeButtonClicked()); +// closeHelpButton.registerEventHandler("Clicked", function() this.closeHelpButtonClicked()); +// helpButton.registerEventHandler("Clicked", function() this.helpButtonClicked()); +// suicideButton.registerEventHandler("Clicked", function() this.suicideButtonClicked()); +// this.editorButton.registerEventHandler("Clicked", function() this.editorButtonClicked()); +// //returnButton.registerEventHandler("Clicked", returnButtonClicked) +// compoundButton.registerEventHandler("Clicked", function() this.toggleCompoundPanel()); +// //compoundPanel.registerEventHandler("Clicked", function() this.closeCompoundPanel()) +// quitButton.registerEventHandler("Clicked", quitButtonClicked); +// this.rootGUIWindow.getChild("PauseMenu").getChild("MainMenuButton").registerEventHandler("Clicked", function() this.menuMainMenuClicked()); +// this.updateLoadButton(); +// } + + +// void HudSystem.update(renderTime){ +// auto player = Entity("player", this.gameState.wrapper); +// auto microbeComponent = getComponent(player, MicrobeComponent); +// auto soundSourceComponent = getComponent(player, SoundSourceComponent); + +// +// auto playerSpecies = MicrobeSystem.getSpeciesComponent(player); +// //notification setting up +// if(b1 == true and t1 < 300){ +// t1 = t1 + 2; +// if(hintsPanelOpned == true){ +// this.hintsButtonClicked(); +// } +// if(t1 == 300){ +// global_activeMicrobeStageHudSystem.chloroplastNotificationdisable(); +// this.hintsButtonClicked(); +// } +// } + +// if(b2 == true and t2 < 300){ +// t2 = t2 + 2; +// if(hintsPanelOpned == true){ +// this.hintsButtonClicked(); +// } +// if(t2 == 300){ +// global_activeMicrobeStageHudSystem.toxinNotificationdisable(); +// this.hintsButtonClicked(); +// } +// } + +// if(b3 == true and t3 < 300){ +// t3 = t3 + 2; +// if(hintsPanelOpned == true){ +// this.hintsButtonClicked(); +// } +// if(t3 == 300){ +// global_activeMicrobeStageHudSystem.editornotificationdisable(); +// } +// } + +// //suicideButton setting up +// auto atp = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("atp")); +// if(atp == 0 and boolean2 == false){ +// this.rootGUIWindow.getChild("SuicideButton").enable(); +// } else if(atp > 0 or boolean2 == true){ +// global_activeMicrobeStageHudSystem.suicideButtondisable(); +// } +// if(boolean == true){ +// MicrobeSystem.kill(player); +// boolean = false; +// boolean2 = true; +// } + +// //Hints setup +// auto glucose = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("glucose")); +// auto ammonia = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("ammonia")); +// auto oxygen = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("oxygen")); +// atpNeeded = math.floor (30 - atp); +// glucoseNeeded = math.floor (16 - glucose); +// ammoniaNeeded = math.floor (12 - ammonia); +// oxygenNeeded = math.floor (15 - oxygen); +// chloroplastNeeded = math.floor (3 - chloroplast_Organelle_Number); +// toxinNeeded = math.floor (3 - toxin_Organelle_Number); + +// if(microbeComponent.hitpoints < microbeComponent.maxHitpoints and healthHint == false and HHO == false){ +// activeHints["healthHint"] = hintN + 1; +// hintN = activeHints["healthHint"]; +// HHO = true; +// } else if (microbeComponent.hitpoints == microbeComponent.maxHitpoints and healthHint == true and HHO == true){ +// activeHints["healthHint"] = null; +// hintN = hintN - 1; +// healthHint = false; +// HHO = false; +// if(next(activeHints) !is null){ +// currentHint = currentHint + 1; +// } +// } + +// if(atp < 15 and atpHint == false and AHO == false){ +// activeHints["atpHint"] = hintN + 1; +// hintN = activeHints["atpHint"]; +// AHO = true; +// } else if(atp > 30 and atpHint == true and AHO == true){ +// activeHints["atpHint"] = null; +// hintN = hintN - 1; +// atpHint = false; +// AHO = false; +// if(next(activeHints) !is null){ +// currentHint = currentHint + 1; +// } +// } + +// if(glucose < 1 and glucoseHint == false and GHO == false){ +// activeHints["glucoseHint"] = hintN + 1; +// hintN = activeHints["glucoseHint"]; +// GHO = true; +// } else if(glucose >= 16 and glucoseHint == true and GHO == true){ +// activeHints["glucoseHint"] = null; +// hintN = hintN - 1; +// glucoseHint = false; +// GHO = false; +// if(next(activeHints) !is null){ +// currentHint = currentHint + 1; +// } +// } + +// if(ammonia < 1 and ammoniaHint == false and AMHO == false){ +// activeHints["ammoniaHint"] = hintN + 1; +// hintN = activeHints["ammoniaHint"]; +// AMHO = true; +// } else if(ammonia >= 12 and ammoniaHint == true and AMHO == true){ +// activeHints["ammoniaHint"] = null; +// hintN = hintN - 1; +// ammoniaHint = false; +// AMHO = false; +// if(next(activeHints) !is null){ +// currentHint = currentHint + 1; +// } +// } + +// if(oxygen < 1 and oxygenHint == false and OHO == false){ +// activeHints["oxygenHint"] = hintN + 1; +// hintN = activeHints["oxygenHint"]; +// OHO = true; +// } else if(oxygen >= 12 and oxygenHint == true and OHO == true){ +// activeHints["oxygenHint"] = null; +// hintN = hintN - 1; +// oxygenHint = false; +// OHO = false; +// if(next(activeHints) !is null){ +// currentHint = currentHint + 1; +// } +// } + +// if(toxin_Organelle_Number < 3 and toxinHint == false and THO == false){ +// activeHints["toxinHint"] = hintN + 1; +// hintN = activeHints["toxinHint"]; +// THO = true; +// } else if(toxin_Organelle_Number >= 3 and toxinHint == true and THO == true){ +// activeHints["toxinHint"] = null; +// hintN = hintN - 1; +// toxinHint = false; +// THO = false; +// if(next(activeHints) !is null){ +// currentHint = currentHint + 1; +// } +// } + +// if(chloroplast_Organelle_Number < 3 and chloroplastHint == false and CHO == false){ +// activeHints["chloroplastHint"] = hintN + 1; +// hintN = activeHints["chloroplastHint"]; +// CHO = true; +// } else if(chloroplast_Organelle_Number >= 3 and chloroplastHint == true and CHO == true){ +// activeHints["chloroplastHint"] = null; +// hintN = hintN - 1; +// chloroplastHint = false; +// CHO = false; +// if(next(activeHints) !is null){ +// currentHint = currentHint + 1; +// } +// } + +// //print (toxin_Organelle_Number .. " " .. chloroplast_Organelle_Number) +// if(healthHint == true){ +// this.rootGUIWindow.getChild("HintsPanel").getChild( +// "HelpText").setText( +// "Your cell is damaged! Collect ammonia and glucose to make amino acids, which can heal it."); +// } + +// if(atpHint == true){ +// this.rootGUIWindow.getChild("HintsPanel").getChild("HelpText").setText( +// "You're running short of ATP! ATP is used to move and engulf. Get " .. atpNeeded .. " to be safe!" +// ); +// } + +// if(glucoseHint == true){ +// this.rootGUIWindow.getChild("HintsPanel").getChild("HelpText").setText( +// "You need more glucose! It's used to make ATP and amino acids. Collect " .. glucoseNeeded .. " to be safe." +// ); +// } + +// if(ammoniaHint == true){ +// this.rootGUIWindow.getChild("HintsPanel").getChild("HelpText").setText( +// "You have little ammonia, used to make amino acids to heal and reproduce. Get " .. ammoniaNeeded .. " more." +// ); +// } + +// if(oxygenHint == true){ +// this.rootGUIWindow.getChild("HintsPanel").getChild("HelpText").setText( +// "You need oxygen to produce ATP and OxyToxy. Collect " .. oxygenNeeded .. " oxygen to do this!" +// ); +// } + +// if(chloroplastHint == true){ +// this.rootGUIWindow.getChild("HintsPanel").getChild("HelpText").setText( +// "Pick " .. chloroplastNeeded .. " green blobs to unlock Chloroplasts, which transform CO2 into glucose and oxygen." +// ); +// } + +// if(toxinHint == true){ +// this.rootGUIWindow.getChild("HintsPanel").getChild("HelpText").setText( +// "Collect " .. toxinNeeded .. " blue blobs to unlock Toxin Vacuoles, used to shoot harmful agents at other cells." +// ); +// } + +// for(hintnam,hintnum in pairs(activeHints)){ +// if(hintnum == currentHint){ +// if(hintnam == "atpHint"){ +// atpHint = true; +// } else { +// atpHint = false; +// } + +// if(hintnam == "healthHint"){ +// healthHint = true; +// } else { +// healthHint = false; +// } + +// if(hintnam == "glucoseHint"){ +// glucoseHint = true; +// } else { +// glucoseHint = false; +// } + +// if(hintnam == "ammoniaHint"){ +// ammoniaHint = true; +// } else { +// ammoniaHint = false; +// } + +// if(hintnam == "oxygenHint"){ +// oxygenHint = true; +// } else { +// oxygenHint = false; +// } + +// if(hintnam == "chloroplastHint"){ +// chloroplastHint = true; +// } else { +// chloroplastHint = false; +// } + +// if(hintnam == "toxinHint"){ +// toxinHint = true; +// } else { +// toxinHint = false; +// } +// } +// } + +// if(next(activeHints) == null){ +// this.rootGUIWindow.getChild("HintsPanel").getChild("HelpText").setText("there is no available hints for now!"); +// } + +// if(currentHint > hintN){ +// currentHint = 1; +// } + +// if(currentHint < 1){ +// currentHint = hintN; +// } + +// //TODO display population in home patch here + +// if(keyCombo(kmp.togglemenu)){ +// this.menuButtonClicked(); +// } else if(keyCombo(kmp.gotoeditor)){ +// this.editorButtonClicked(); +// } else if(keyCombo(kmp.shootoxytoxy)){ +// MicrobeSystem.emitAgent(player, CompoundRegistry.getCompoundId("oxytoxy"), 3); +// } else if(keyCombo(kmp.reproduce)){ +// MicrobeSystem.readyToReproduce(player); +// } +// auto direction = Vector3(0, 0, 0); +// if(keyCombo(kmp.forward)){ +// soundSourceComponent.playSound("microbe-movement-2"); +// } +// if(keyCombo(kmp.backward)){ +// soundSourceComponent.playSound("microbe-movement-2"); +// } +// if(keyCombo(kmp.leftward)){ +// soundSourceComponent.playSound("microbe-movement-1"); +// } +// if(keyCombo(kmp.screenshot)){ +// Engine.screenShot("screenshot.png"); +// } +// if(keyCombo(kmp.rightward)){ +// soundSourceComponent.playSound("microbe-movement-1"); +// } +// if((Engine.keyboard.wasKeyPressed(KEYCODE.KC_G))){ +// MicrobeSystem.toggleEngulfMode(player); +// } + + +// // Changing the camera height according to the player input. +// // Now in the c++ system +// // auto offset = getComponent(CAMERA_NAME, this.gameState, OgreCameraComponent).properties.offset; + +// // if(Engine.mouse.scrollChange() ~= 0){ +// // this.scrollChange = this.scrollChange + Engine.mouse.scrollChange() * CAMERA_VERTICAL_SPEED; +// // } else if(keyCombo(kmp.plus) or keyCombo(kmp.add)){ +// // this.scrollChange = this.scrollChange - 5; +// // } else if(keyCombo(kmp.minus) or keyCombo(kmp.subtract)){ +// // this.scrollChange = this.scrollChange + 5; +// // } + + +// // auto newZVal = offset.z; +// // if(this.scrollChange >= 1){ +// // newZVal = newZVal + 2.5; +// // this.scrollChange = this.scrollChange - 1; +// // } else if(this.scrollChange <= -1){ +// // newZVal = newZVal - 2.5; +// // this.scrollChange = this.scrollChange + 1; +// // } + +// // if(newZVal < CAMERA_MIN_HEIGHT){ +// // newZVal = CAMERA_MIN_HEIGHT; +// // this.scrollChange = 0; +// // } else if(newZVal > CAMERA_MAX_HEIGHT){ +// // newZVal = CAMERA_MAX_HEIGHT; +// // this.scrollChange = 0; +// // } + +// // offset.z = newZVal; +// } + + + +// ------------------------------------ // +// Wrappers for calling GUI update things from random places + +void showReproductionDialog(GameWorld@ world){ + + cast(world.GetScriptSystem("MicrobeStageHudSystem")). + showReproductionDialog(); +} + +void showMessage(const string &in msg){ + LOG_INFO(msg + " (note, in-game messages currently disabled)"); + //auto messagePanel = Engine.currentGameState().rootGUIWindow().getChild("MessagePanel") + //messagePanel.getChild("MessageLabel").setText(msg) + //messagePanel.show() +} + +// //Event handlers + +// void HudSystem.hintsButtonClicked(){ +// if(hintsPanelOpned == false){ +// this.rootGUIWindow.getChild("HintsPanel").show(); +// this.rootGUIWindow.getChild("HintsButton").setText(""); +// this.rootGUIWindow.getChild("HintsButton").getChild("HintsIcon").hide(); +// this.rootGUIWindow.getChild("HintsButton").getChild("HintsContractIcon").show(); +// this.rootGUIWindow.getChild("HintsButton").setProperty("Hide the hints panel", "TooltipText"); +// hintsPanelOpned = true; +// } else if(hintsPanelOpned == true){ +// this.rootGUIWindow.getChild("HintsPanel").hide(); +// this.rootGUIWindow.getChild("HintsButton").setText("Hints"); +// this.rootGUIWindow.getChild("HintsButton").getChild("HintsIcon").show(); +// this.rootGUIWindow.getChild("HintsButton").getChild("HintsContractIcon").hide(); +// this.rootGUIWindow.getChild("HintsButton").setProperty("Open the hints panel", "TooltipText"); +// hintsPanelOpned = false; +// } +// } + +// void HudSystem.nextHintButtonClicked(){ +// currentHint = currentHint + 1; +// } +// void HudSystem.lastHintButtonClicked(){ +// currentHint = currentHint - 1; +// } +// void HudSystem.saveButtonClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// Engine.save("quick.sav"); +// print("Game Saved"); +// //Because using update load button here doesn't seem to work unless you press save twice +// this.rootGUIWindow.getChild("PauseMenu").getChild("LoadGameButton").enable(); +// } +// void HudSystem.loadButtonClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// Engine.load("quick.sav"); +// print("Game loaded"); +// this.rootGUIWindow.getChild("PauseMenu").hide(); +// this.menuOpen = false; +// } + +// void HudSystem.menuButtonClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// print("played sound"); +// this.rootGUIWindow.getChild("PauseMenu").show(); +// this.rootGUIWindow.getChild("PauseMenu").moveToFront(); +// this.updateLoadButton(); +// Engine.pauseGame(); +// this.menuOpen = true; +// } + +// void HudSystem.resumeButtonClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// print("played sound"); +// this.rootGUIWindow.getChild("PauseMenu").hide(); +// this.updateLoadButton(); +// Engine.resumeGame(); +// this.menuOpen = false; +// } + + +// void HudSystem.toggleCompoundPanel(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// if(this.compoundsOpen){ +// this.rootGUIWindow.getChild("CompoundPanel").hide(); +// this.rootGUIWindow.getChild("CompoundExpandButton").getChild("CompoundExpandIcon").hide(); +// this.rootGUIWindow.getChild("CompoundExpandButton").getChild("CompoundContractIcon").show(); +// this.compoundsOpen = false; +// } else { +// this.rootGUIWindow.getChild("CompoundPanel").show(); +// this.rootGUIWindow.getChild("CompoundExpandButton").getChild("CompoundExpandIcon").show(); +// this.rootGUIWindow.getChild("CompoundExpandButton").getChild("CompoundContractIcon").hide(); +// this.compoundsOpen = true; +// } +// } + + + + + + +// void HudSystem.helpButtonClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// this.rootGUIWindow.getChild("PauseMenu").getChild("HelpPanel").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("CloseHelpButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("ResumeButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("QuicksaveButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("SaveGameButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("LoadGameButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("StatsButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("HelpButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("OptionsButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("MainMenuButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("QuitButton").hide(); +// this.helpOpen = not this.helpOpen; +// } + + +// void HudSystem.closeHelpButtonClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// this.rootGUIWindow.getChild("PauseMenu").getChild("HelpPanel").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("CloseHelpButton").hide(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("ResumeButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("QuicksaveButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("SaveGameButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("LoadGameButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("StatsButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("HelpButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("OptionsButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("MainMenuButton").show(); +// this.rootGUIWindow.getChild("PauseMenu").getChild("QuitButton").show(); +// this.helpOpen = not this.helpOpen; +// } + +// void HudSystem.menuMainMenuClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// g_luaEngine.setCurrentGameState(GameState.MAIN_MENU); +// } + + +// void HudSystem.editorButtonClicked(){ +// auto player = Entity("player", this.gameState.wrapper); +// // Return the first cell to its normal, non duplicated cell arangement. +// SpeciesSystem.restoreOrganelleLayout(player, MicrobeSystem.getSpeciesComponent(player)); + +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// this.editorButton.disable(); +// b3 = false; +// t3 = 0; +// g_luaEngine.setCurrentGameState(GameState.MICROBE_EDITOR); +// } + +// // //[[ +// // void HudSystem.returnButtonClicked(){ +// // getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// // //Engine.currentGameState().rootGUIWindow().getChild("MenuPanel").hide() +// // if(Engine.currentGameState().name() == "microbe"){ +// // Engine.currentGameState().rootGUIWindow().getChild("HelpPanel").hide(); +// // Engine.currentGameState().rootGUIWindow().getChild("MessagePanel").hide(); +// // Engine.currentGameState().rootGUIWindow().getChild("ReproductionPanel").hide(); +// // Engine.resumeGame(); +// // else if(Engine.currentGameState().name() == "microbe_editor"){ +// // Engine.currentGameState().rootGUIWindow().getChild("SaveLoadPanel").hide() +// // } +// // } //]] + +// void quitButtonClicked(){ +// getComponent("gui_sounds", this.gameState, SoundSourceComponent).playSound("button-hover-click"); +// Engine.quit(); +// } diff --git a/scripts/microbe_stage/microbe_stage_hud.lua b/scripts/microbe_stage/microbe_stage_hud.lua deleted file mode 100644 index 410b797675e..00000000000 --- a/scripts/microbe_stage/microbe_stage_hud.lua +++ /dev/null @@ -1,770 +0,0 @@ --- --- TODO: merge the common things in microbe_stage_tutorial_hud --- notification setting up -t1 = 0 -t2 = 0 -t3 = 0 -b1 = false -b2 = false -b3 = false ---suicideButton setting up -boolean = false -boolean2 = false ---hints setting up -hintsPanelOpned = false -healthHint = false -atpHint = false -glucoseHint = false -ammoniaHint = false -oxygenHint = false -toxinHint = false -chloroplastHint = false -activeHints = {} -hintN = 0 -currentHint = 1 -HHO = false -AHO = false -GHO = false -AMHO = false -OHO = false -THO = false -CHO = false -glucoseNeeded = 0 -atpNeeded = 0 -ammoniaNeeded = 0 -oxygenNeeded = 0 -chloroplastNeeded = 0 -toxinNeeded = 0 - - -- Camera limits - CAMERA_MIN_HEIGHT = 20 - CAMERA_MAX_HEIGHT = 120 - CAMERA_VERTICAL_SPEED = 0.015 - --- Updates the hud with relevant information - -HudSystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - - self.compoundListBox = nil - self.hitpointsCountLabel = nil - self.hitpointsMaxLabel = nil - self.hitpointsBar = nil - self.compoundListItems = {} - self.rootGuiWindow = nil - self.populationNumberLabel = nil - self.rootGUIWindow = nil - self.scrollChange = 0 - - end -) - --- This methods would get overriden by their duplicates below. ---[[ -function HudSystem:init(gameState) - LuaSystem.init(self, "HudSystem", gameState) -end - -function HudSystem:update(renderTime, logicTime) - -- TODO: use the QuickSaveSystem here? is this duplicated functionality? - local saveDown = Engine.keyboard:isKeyDown(KEYCODE.KC_F4) - local loadDown = Engine.keyboard:isKeyDown(KEYCODE.KC_F10) - if saveDown and not self.saveDown then - Engine:save("quick.sav") - end - if loadDown and not self.loadDown then - Engine:load("quick.sav") - end - self.saveDown = saveDown - self.loadDown = loadDown -end -]] - -global_if_already_displayed = false - -function HudSystem:activate() - global_activeMicrobeStageHudSystem = self -- Global reference for event handlers - - lockedMap = Engine:playerData():lockedMap() - if lockedMap ~= nil and not lockedMap:isLocked("Toxin") and not ss and not global_if_already_displayed then - showMessage("'E' Releases Toxin") - global_if_already_displayed = true - end - self.helpOpen = false - self.menuOpen = false - self.compoundsOpen = true - Engine:resumeGame() - self:updateLoadButton() - - self:chloroplastNotificationdisable() - self:toxinNotificationdisable() - self:editornotificationdisable() -end - -function HudSystem:init(gameState) - LuaSystem.init(self, "MicrobeStageHudSystem", gameState) - self.rootGUIWindow = gameState:rootGUIWindow() - self.hitpointsBar = self.rootGUIWindow:getChild("HealthPanel"):getChild("LifeBar") - self.hitpointsCountLabel = self.hitpointsBar:getChild("NumberLabel") - self.hitpointsMaxLabel = self.rootGUIWindow:getChild("HealthPanel"):getChild("HealthTotal") - self.hitpointsBar:setProperty("ThriveGeneric/HitpointsBar", "FillImage") - local menuButton = self.rootGUIWindow:getChild("MenuButton") - local saveButton = self.rootGUIWindow:getChild("PauseMenu"):getChild("QuicksaveButton") - local loadButton = self.rootGUIWindow:getChild("PauseMenu"):getChild("LoadGameButton") - local resumeButton = self.rootGUIWindow:getChild("PauseMenu"):getChild("ResumeButton") - local closeHelpButton = self.rootGUIWindow:getChild("PauseMenu"):getChild("CloseHelpButton") - local chloroplast_unlock_notification = self.rootGUIWindow:getChild("chloroplastUnlockNotification") - local toxin_unlock_notification = self.rootGUIWindow:getChild("toxinUnlockNotification") - local nextHint = self.rootGUIWindow:getChild("HintsPanel"):getChild("NextHint") - local lastHint = self.rootGUIWindow:getChild("HintsPanel"):getChild("LastHint") - --local collapseButton = self.rootGUIWindow:getChild() collapseButtonClicked - local hintsButton = self.rootGUIWindow:getChild("HintsButton") - local helpButton = self.rootGUIWindow:getChild("PauseMenu"):getChild("HelpButton") - local helpPanel = self.rootGUIWindow:getChild("PauseMenu"):getChild("HelpPanel") - self.editorButton = self.rootGUIWindow:getChild("EditorButton") - local suicideButton = self.rootGUIWindow:getChild("SuicideButton") - --local returnButton = self.rootGUIWindow:getChild("MenuButton") - local compoundButton = self.rootGUIWindow:getChild("CompoundExpandButton") - --local compoundPanel = self.rootGUIWindow:getChild("CompoundsOpen") - local quitButton = self.rootGUIWindow:getChild("PauseMenu"):getChild("QuitButton") - nextHint:registerEventHandler("Clicked", function() self:nextHintButtonClicked() end) - lastHint:registerEventHandler("Clicked", function() self:lastHintButtonClicked() end) - hintsButton:registerEventHandler("Clicked", function() self:hintsButtonClicked() end) - saveButton:registerEventHandler("Clicked", function() self:saveButtonClicked() end) - loadButton:registerEventHandler("Clicked", function() self:loadButtonClicked() end) - menuButton:registerEventHandler("Clicked", function() self:menuButtonClicked() end) - resumeButton:registerEventHandler("Clicked", function() self:resumeButtonClicked() end) - closeHelpButton:registerEventHandler("Clicked", function() self:closeHelpButtonClicked() end) - helpButton:registerEventHandler("Clicked", function() self:helpButtonClicked() end) - suicideButton:registerEventHandler("Clicked", function() self:suicideButtonClicked() end) - self.editorButton:registerEventHandler("Clicked", function() self:editorButtonClicked() end) - --returnButton:registerEventHandler("Clicked", returnButtonClicked) - compoundButton:registerEventHandler("Clicked", function() self:toggleCompoundPanel() end) - --compoundPanel:registerEventHandler("Clicked", function() self:closeCompoundPanel() end) - quitButton:registerEventHandler("Clicked", quitButtonClicked) - self.rootGUIWindow:getChild("PauseMenu"):getChild("MainMenuButton"):registerEventHandler("Clicked", function() self:menuMainMenuClicked() end) - self:updateLoadButton(); - - self.atpBar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("ATPBar"):getChild("ATPBar") - self.atpCountLabel = self.atpBar:getChild("NumberLabel") - self.atpMaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("ATPBar"):getChild("ATPTotal") - self.atpBar:setProperty("ThriveGeneric/ATPBar", "FillImage") - - self.atpCountLabel2 = self.rootGUIWindow:getChild("HealthPanel"):getChild("ATPValue") - - self.oxygenBar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("OxygenBar"):getChild("OxygenBar") - self.oxygenCountLabel = self.oxygenBar:getChild("NumberLabel") - self.oxygenMaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("OxygenBar"):getChild("OxygenTotal") - self.oxygenBar:setProperty("ThriveGeneric/OxygenBar", "FillImage") - - self.aminoacidsBar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("AminoAcidsBar"):getChild("AminoAcidsBar") - self.aminoacidsCountLabel = self.aminoacidsBar:getChild("NumberLabel") - self.aminoacidsMaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("AminoAcidsBar"):getChild("AminoAcidsTotal") - self.aminoacidsBar:setProperty("ThriveGeneric/AminoAcidsBar", "FillImage") - - self.ammoniaBar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("AmmoniaBar"):getChild("AmmoniaBar") - self.ammoniaCountLabel = self.ammoniaBar:getChild("NumberLabel") - self.ammoniaMaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("AmmoniaBar"):getChild("AmmoniaTotal") - self.ammoniaBar:setProperty("ThriveGeneric/AmmoniaBar", "FillImage") - - self.glucoseBar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("GlucoseBar"):getChild("GlucoseBar") - self.glucoseCountLabel = self.glucoseBar:getChild("NumberLabel") - self.glucoseMaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("GlucoseBar"):getChild("GlucoseTotal") - self.glucoseBar:setProperty("ThriveGeneric/GlucoseBar", "FillImage") - - self.co2Bar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("CO2Bar"):getChild("CO2Bar") - self.co2CountLabel = self.co2Bar:getChild("NumberLabel") - self.co2MaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("CO2Bar"):getChild("CO2Total") - self.co2Bar:setProperty("ThriveGeneric/CO2Bar", "FillImage") - - self.fattyacidsBar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("FattyAcidsBar"):getChild("FattyAcidsBar") - self.fattyacidsCountLabel = self.fattyacidsBar:getChild("NumberLabel") - self.fattyacidsMaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("FattyAcidsBar"):getChild("FattyAcidsTotal") - self.fattyacidsBar:setProperty("ThriveGeneric/FattyAcidsBar", "FillImage") - - self.oxytoxyBar = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("OxyToxyNTBar"):getChild("OxyToxyNTBar") - self.oxytoxyCountLabel = self.oxytoxyBar:getChild("NumberLabel") - self.oxytoxyMaxLabel = self.rootGUIWindow:getChild("CompoundPanel"):getChild("CompoundScroll"):getChild("OxyToxyNTBar"):getChild("OxyToxyNTTotal") - self.oxytoxyBar:setProperty("ThriveGeneric/OxyToxyBar", "FillImage") -end - - -function HudSystem:update(renderTime) - local player = Entity.new("player", self.gameState.wrapper) - local microbeComponent = getComponent(player, MicrobeComponent) - local soundSourceComponent = getComponent(player, SoundSourceComponent) - - self.hitpointsBar:progressbarSetProgress(microbeComponent.hitpoints/microbeComponent.maxHitpoints) - self.hitpointsCountLabel:setText("".. math.floor(microbeComponent.hitpoints)) - self.hitpointsMaxLabel:setText("/ ".. math.floor(microbeComponent.maxHitpoints)) - - self.atpBar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("atp"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("atp")))) - self.atpCountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("atp")))) - self.atpMaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("atp")))) - - self.atpCountLabel2:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("atp")))) - - self.oxygenBar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("oxygen"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("oxygen")))) - self.oxygenCountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("oxygen")))) - self.oxygenMaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("oxygen")))) - - self.aminoacidsBar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("aminoacids"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("aminoacids")))) - self.aminoacidsCountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("aminoacids")))) - self.aminoacidsMaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("aminoacids")))) - - self.ammoniaBar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("ammonia"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("ammonia")))) - self.ammoniaCountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("ammonia")))) - self.ammoniaMaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("ammonia")))) - - self.glucoseBar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("glucose"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("glucose")))) - self.glucoseCountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("glucose")))) - self.glucoseMaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("glucose")))) - - self.co2Bar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("co2"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("co2")))) - self.co2CountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("co2")))) - self.co2MaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("co2")))) - - self.fattyacidsBar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("fattyacids"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("fattyacids")))) - self.fattyacidsCountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("fattyacids")))) - self.fattyacidsMaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("fattyacids")))) - - self.oxytoxyBar:progressbarSetProgress(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("oxytoxy"))/(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("oxytoxy")))) - self.oxytoxyCountLabel:setText("".. math.floor(MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("oxytoxy")))) - self.oxytoxyMaxLabel:setText("/ ".. math.floor(microbeComponent.capacity/CompoundRegistry.getCompoundUnitVolume(CompoundRegistry.getCompoundId("oxytoxy")))) - - local playerSpecies = MicrobeSystem.getSpeciesComponent(player) - --notification setting up - if b1 == true and t1 < 300 then - t1 = t1 + 2 - if hintsPanelOpned == true then - self:hintsButtonClicked() - end - if t1 == 300 then - global_activeMicrobeStageHudSystem:chloroplastNotificationdisable() - self:hintsButtonClicked() - end - end - - if b2 == true and t2 < 300 then - t2 = t2 + 2 - if hintsPanelOpned == true then - self:hintsButtonClicked() - end - if t2 == 300 then - global_activeMicrobeStageHudSystem:toxinNotificationdisable() - self:hintsButtonClicked() - end - end - - if b3 == true and t3 < 300 then - t3 = t3 + 2 - if hintsPanelOpned == true then - self:hintsButtonClicked() - end - if t3 == 300 then - global_activeMicrobeStageHudSystem:editornotificationdisable() - end - end - - --suicideButton setting up - local atp = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("atp")) - if atp == 0 and boolean2 == false then - self.rootGUIWindow:getChild("SuicideButton"):enable() - elseif atp > 0 or boolean2 == true then - global_activeMicrobeStageHudSystem:suicideButtondisable() - end - if boolean == true then - MicrobeSystem.kill(player) - boolean = false - boolean2 = true - end - - --Hints setup - local glucose = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("glucose")) - local ammonia = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("ammonia")) - local oxygen = MicrobeSystem.getCompoundAmount(player, CompoundRegistry.getCompoundId("oxygen")) - atpNeeded = math.floor (30 - atp) - glucoseNeeded = math.floor (16 - glucose) - ammoniaNeeded = math.floor (12 - ammonia) - oxygenNeeded = math.floor (15 - oxygen) - chloroplastNeeded = math.floor (3 - chloroplast_Organelle_Number) - toxinNeeded = math.floor (3 - toxin_Organelle_Number) - - if microbeComponent.hitpoints < microbeComponent.maxHitpoints and healthHint == false and HHO == false then - activeHints["healthHint"] = hintN + 1 - hintN = activeHints["healthHint"] - HHO = true - elseif microbeComponent.hitpoints == microbeComponent.maxHitpoints and healthHint == true and HHO == true then - activeHints["healthHint"] = nil - hintN = hintN - 1 - healthHint = false - HHO = false - if next(activeHints) ~= nil then - currentHint = currentHint + 1 - end - end - - if atp < 15 and atpHint == false and AHO == false then - activeHints["atpHint"] = hintN + 1 - hintN = activeHints["atpHint"] - AHO = true - elseif atp > 30 and atpHint == true and AHO == true then - activeHints["atpHint"] = nil - hintN = hintN - 1 - atpHint = false - AHO = false - if next(activeHints) ~= nil then - currentHint = currentHint + 1 - end - end - - if glucose < 1 and glucoseHint == false and GHO == false then - activeHints["glucoseHint"] = hintN + 1 - hintN = activeHints["glucoseHint"] - GHO = true - elseif glucose >= 16 and glucoseHint == true and GHO == true then - activeHints["glucoseHint"] = nil - hintN = hintN - 1 - glucoseHint = false - GHO = false - if next(activeHints) ~= nil then - currentHint = currentHint + 1 - end - end - - if ammonia < 1 and ammoniaHint == false and AMHO == false then - activeHints["ammoniaHint"] = hintN + 1 - hintN = activeHints["ammoniaHint"] - AMHO = true - elseif ammonia >= 12 and ammoniaHint == true and AMHO == true then - activeHints["ammoniaHint"] = nil - hintN = hintN - 1 - ammoniaHint = false - AMHO = false - if next(activeHints) ~= nil then - currentHint = currentHint + 1 - end - end - - if oxygen < 1 and oxygenHint == false and OHO == false then - activeHints["oxygenHint"] = hintN + 1 - hintN = activeHints["oxygenHint"] - OHO = true - elseif oxygen >= 12 and oxygenHint == true and OHO == true then - activeHints["oxygenHint"] = nil - hintN = hintN - 1 - oxygenHint = false - OHO = false - if next(activeHints) ~= nil then - currentHint = currentHint + 1 - end - end - - if toxin_Organelle_Number < 3 and toxinHint == false and THO == false then - activeHints["toxinHint"] = hintN + 1 - hintN = activeHints["toxinHint"] - THO = true - elseif toxin_Organelle_Number >= 3 and toxinHint == true and THO == true then - activeHints["toxinHint"] = nil - hintN = hintN - 1 - toxinHint = false - THO = false - if next(activeHints) ~= nil then - currentHint = currentHint + 1 - end - end - - if chloroplast_Organelle_Number < 3 and chloroplastHint == false and CHO == false then - activeHints["chloroplastHint"] = hintN + 1 - hintN = activeHints["chloroplastHint"] - CHO = true - elseif chloroplast_Organelle_Number >= 3 and chloroplastHint == true and CHO == true then - activeHints["chloroplastHint"] = nil - hintN = hintN - 1 - chloroplastHint = false - CHO = false - if next(activeHints) ~= nil then - currentHint = currentHint + 1 - end - end - - --print (toxin_Organelle_Number .. " " .. chloroplast_Organelle_Number) - if healthHint == true then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText( - "Your cell is damaged! Collect ammonia and glucose to make amino acids, which can heal it." - ) - end - - if atpHint == true then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText( - "You're running short of ATP! ATP is used to move and engulf. Get " .. atpNeeded .. " to be safe!" - ) - end - - if glucoseHint == true then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText( - "You need more glucose! It's used to make ATP and amino acids. Collect " .. glucoseNeeded .. " to be safe." - ) - end - - if ammoniaHint == true then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText( - "You have little ammonia, used to make amino acids to heal and reproduce. Get " .. ammoniaNeeded .. " more." - ) - end - - if oxygenHint == true then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText( - "You need oxygen to produce ATP and OxyToxy. Collect " .. oxygenNeeded .. " oxygen to do this!" - ) - end - - if chloroplastHint == true then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText( - "Pick " .. chloroplastNeeded .. " green blobs to unlock Chloroplasts, which transform CO2 into glucose and oxygen." - ) - end - - if toxinHint == true then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText( - "Collect " .. toxinNeeded .. " blue blobs to unlock Toxin Vacuoles, used to shoot harmful agents at other cells." - ) - end - - for hintnam,hintnum in pairs(activeHints) do - if hintnum == currentHint then - if hintnam == "atpHint" then - atpHint = true - else - atpHint = false - end - - if hintnam == "healthHint" then - healthHint = true - else - healthHint = false - end - - if hintnam == "glucoseHint" then - glucoseHint = true - else - glucoseHint = false - end - - if hintnam == "ammoniaHint" then - ammoniaHint = true - else - ammoniaHint = false - end - - if hintnam == "oxygenHint" then - oxygenHint = true - else - oxygenHint = false - end - - if hintnam == "chloroplastHint" then - chloroplastHint = true - else - chloroplastHint = false - end - - if hintnam == "toxinHint" then - toxinHint = true - else - toxinHint = false - end - end - end - - if next(activeHints) == nil then - self.rootGUIWindow:getChild("HintsPanel"):getChild("HelpText"):setText("there is no available hints for now!") - end - - if currentHint > hintN then - currentHint = 1 - end - - if currentHint < 1 then - currentHint = hintN - end - - --TODO display population in home patch here - - if keyCombo(kmp.togglemenu) then - self:menuButtonClicked() - elseif keyCombo(kmp.gotoeditor) then - self:editorButtonClicked() - elseif keyCombo(kmp.shootoxytoxy) then - MicrobeSystem.emitAgent(player, CompoundRegistry.getCompoundId("oxytoxy"), 3) - elseif keyCombo(kmp.reproduce) then - MicrobeSystem.readyToReproduce(player) - end - local direction = Vector3(0, 0, 0) - if keyCombo(kmp.forward) then - soundSourceComponent:playSound("microbe-movement-2") - end - if keyCombo(kmp.backward) then - soundSourceComponent:playSound("microbe-movement-2") - end - if keyCombo(kmp.leftward) then - soundSourceComponent:playSound("microbe-movement-1") - end - if keyCombo(kmp.screenshot) then - Engine:screenShot("screenshot.png") - end - if keyCombo(kmp.rightward) then - soundSourceComponent:playSound("microbe-movement-1") - end - if (Engine.keyboard:wasKeyPressed(KEYCODE.KC_G)) then - MicrobeSystem.toggleEngulfMode(player) - end - -- Changing the camera height according to the player input. - local offset = getComponent(CAMERA_NAME, self.gameState, OgreCameraComponent).properties.offset - - if Engine.mouse:scrollChange() ~= 0 then - self.scrollChange = self.scrollChange + Engine.mouse:scrollChange() * CAMERA_VERTICAL_SPEED - elseif keyCombo(kmp.plus) or keyCombo(kmp.add) then - self.scrollChange = self.scrollChange - 5 - elseif keyCombo(kmp.minus) or keyCombo(kmp.subtract) then - self.scrollChange = self.scrollChange + 5 - end - - local newZVal = offset.z - if self.scrollChange >= 1 then - newZVal = newZVal + 2.5 - self.scrollChange = self.scrollChange - 1 - elseif self.scrollChange <= -1 then - newZVal = newZVal - 2.5 - self.scrollChange = self.scrollChange + 1 - end - - if newZVal < CAMERA_MIN_HEIGHT then - newZVal = CAMERA_MIN_HEIGHT - self.scrollChange = 0 - elseif newZVal > CAMERA_MAX_HEIGHT then - newZVal = CAMERA_MAX_HEIGHT - self.scrollChange = 0 - end - - offset.z = newZVal -end - -function showReproductionDialog() - assert(global_activeMicrobeStageHudSystem ~= nil, - "no global active global_activeMicrobeStageHudSystem") - assert(global_activeMicrobeStageHudSystem.showReproductionDialog) - global_activeMicrobeStageHudSystem:showReproductionDialog() -end - -function HudSystem:showReproductionDialog() - -- print("Reproduction Dialog called but currently disabled. Is it needed? Note that the editor button has been enabled") - --global_activeMicrobeStageHudSystem.rootGUIWindow:getChild("ReproductionPanel"):show() - if b3 == false then - getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("microbe-pickup-organelle") -self.rootGUIWindow:getChild("editornotification"):show() -b3 = true -end - self.editorButton:enable() -end - -function showMessage(msg) - print(msg.." (note, in-game messages currently disabled)") - --local messagePanel = Engine:currentGameState():rootGUIWindow():getChild("MessagePanel") - --messagePanel:getChild("MessageLabel"):setText(msg) - --messagePanel:show() -end - -function HudSystem:updateLoadButton() - if Engine:fileExists("quick.sav") then - self.rootGUIWindow:getChild("PauseMenu"):getChild("LoadGameButton"):enable(); - else - self.rootGUIWindow:getChild("PauseMenu"):getChild("LoadGameButton"):disable(); - end -end - ---Event handlers - -function HudSystem:hintsButtonClicked() -if hintsPanelOpned == false then -self.rootGUIWindow:getChild("HintsPanel"):show() -self.rootGUIWindow:getChild("HintsButton"):setText("") -self.rootGUIWindow:getChild("HintsButton"):getChild("HintsIcon"):hide() -self.rootGUIWindow:getChild("HintsButton"):getChild("HintsContractIcon"):show() -self.rootGUIWindow:getChild("HintsButton"):setProperty("Hide the hints panel", "TooltipText") -hintsPanelOpned = true - elseif hintsPanelOpned == true then -self.rootGUIWindow:getChild("HintsPanel"):hide() -self.rootGUIWindow:getChild("HintsButton"):setText("Hints") -self.rootGUIWindow:getChild("HintsButton"):getChild("HintsIcon"):show() -self.rootGUIWindow:getChild("HintsButton"):getChild("HintsContractIcon"):hide() -self.rootGUIWindow:getChild("HintsButton"):setProperty("Open the hints panel", "TooltipText") -hintsPanelOpned = false -end -end -function HudSystem:nextHintButtonClicked() -currentHint = currentHint + 1 -end -function HudSystem:lastHintButtonClicked() -currentHint = currentHint - 1 -end -function HudSystem:saveButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - Engine:save("quick.sav") - print("Game Saved"); - --Because using update load button here doesn't seem to work unless you press save twice - self.rootGUIWindow:getChild("PauseMenu"):getChild("LoadGameButton"):enable(); -end -function HudSystem:loadButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - Engine:load("quick.sav") - print("Game loaded"); - self.rootGUIWindow:getChild("PauseMenu"):hide() - self.menuOpen = false -end - -function HudSystem:menuButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - print("played sound") - self.rootGUIWindow:getChild("PauseMenu"):show() - self.rootGUIWindow:getChild("PauseMenu"):moveToFront() - self:updateLoadButton(); - Engine:pauseGame() - self.menuOpen = true -end - -function HudSystem:resumeButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - print("played sound") - self.rootGUIWindow:getChild("PauseMenu"):hide() - self:updateLoadButton(); - Engine:resumeGame() - self.menuOpen = false -end - - -function HudSystem:toggleCompoundPanel() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - if self.compoundsOpen then - self.rootGUIWindow:getChild("CompoundPanel"):hide() - self.rootGUIWindow:getChild("CompoundExpandButton"):getChild("CompoundExpandIcon"):hide() - self.rootGUIWindow:getChild("CompoundExpandButton"):getChild("CompoundContractIcon"):show() - self.compoundsOpen = false - else - self.rootGUIWindow:getChild("CompoundPanel"):show() - self.rootGUIWindow:getChild("CompoundExpandButton"):getChild("CompoundExpandIcon"):show() - self.rootGUIWindow:getChild("CompoundExpandButton"):getChild("CompoundContractIcon"):hide() - self.compoundsOpen = true - end -end - -function HudSystem:chloroplastNotificationenable() -getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("microbe-pickup-organelle") -self.rootGUIWindow:getChild("chloroplastUnlockNotification"):show() -b1 = true -self.rootGUIWindow:getChild("toxinUnlockNotification"):hide() -end - -function HudSystem:chloroplastNotificationdisable() -self.rootGUIWindow:getChild("chloroplastUnlockNotification"):hide() -end - -function HudSystem:toxinNotificationenable() -getComponent("gui_sounds", g_luaEngine.currentGameState, SoundSourceComponent - ):playSound("microbe-pickup-organelle") -self.rootGUIWindow:getChild("toxinUnlockNotification"):show() -b2 = true -self.rootGUIWindow:getChild("chloroplastUnlockNotification"):hide() -end - -function HudSystem:toxinNotificationdisable() -self.rootGUIWindow:getChild("toxinUnlockNotification"):hide() -end -function HudSystem:editornotificationdisable() -self.rootGUIWindow:getChild("editornotification"):hide() -end -function HudSystem:helpButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - self.rootGUIWindow:getChild("PauseMenu"):getChild("HelpPanel"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("CloseHelpButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("ResumeButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("QuicksaveButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("SaveGameButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("LoadGameButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("StatsButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("HelpButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("OptionsButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("MainMenuButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("QuitButton"):hide() - self.helpOpen = not self.helpOpen -end - -function HudSystem:suicideButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - if boolean2 == false then -boolean = true -end - end - function HudSystem:suicideButtondisable() - self.rootGUIWindow:getChild("SuicideButton"):disable() - end - function HudSystem:suicideButtonreset() - boolean2 = false - end -function HudSystem:closeHelpButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - self.rootGUIWindow:getChild("PauseMenu"):getChild("HelpPanel"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("CloseHelpButton"):hide() - self.rootGUIWindow:getChild("PauseMenu"):getChild("ResumeButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("QuicksaveButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("SaveGameButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("LoadGameButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("StatsButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("HelpButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("OptionsButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("MainMenuButton"):show() - self.rootGUIWindow:getChild("PauseMenu"):getChild("QuitButton"):show() - self.helpOpen = not self.helpOpen -end - -function HudSystem:menuMainMenuClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - g_luaEngine:setCurrentGameState(GameState.MAIN_MENU) -end - - -function HudSystem:editorButtonClicked() - local player = Entity.new("player", self.gameState.wrapper) - -- Return the first cell to its normal, non duplicated cell arangement. - SpeciesSystem.restoreOrganelleLayout(player, MicrobeSystem.getSpeciesComponent(player)) - - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - self.editorButton:disable() - b3 = false - t3 = 0 - g_luaEngine:setCurrentGameState(GameState.MICROBE_EDITOR) -end - ---[[ -function HudSystem:returnButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - --Engine:currentGameState():rootGUIWindow():getChild("MenuPanel"):hide() - if Engine:currentGameState():name() == "microbe" then - Engine:currentGameState():rootGUIWindow():getChild("HelpPanel"):hide() - Engine:currentGameState():rootGUIWindow():getChild("MessagePanel"):hide() - Engine:currentGameState():rootGUIWindow():getChild("ReproductionPanel"):hide() - Engine:resumeGame() - elseif Engine:currentGameState():name() == "microbe_editor" then - Engine:currentGameState():rootGUIWindow():getChild("SaveLoadPanel"):hide() - end -end --]] - -function quitButtonClicked() - getComponent("gui_sounds", self.gameState, SoundSourceComponent):playSound("button-hover-click") - Engine:quit() -end diff --git a/scripts/microbe_stage/movement_organelle.as b/scripts/microbe_stage/movement_organelle.as new file mode 100644 index 00000000000..4bfc5f09986 --- /dev/null +++ b/scripts/microbe_stage/movement_organelle.as @@ -0,0 +1,264 @@ +#include "organelle_component.as" +#include "microbe_operations.as" + +// Enables a microbe to move and turn + +// See organelle_component.as for more information about the +// organelle component methods and the arguments they receive. + +// Calculate the momentum of the movement organelle based on angle towards nucleus +Float3 calculateForce(int q, int r, float momentum){ + Float3 organelle = Hex::axialToCartesian(q, r); + Float3 nucleus = Hex::axialToCartesian(0, 0); + auto delta = nucleus - organelle; + return delta.Normalize() * momentum; +} + +//! \todo flagellum animation +class MovementOrganelle : OrganelleComponent{ + + // Constructor + // + // @param momentum + // The force this organelle can exert to move a microbe. + // + // @param torque + // The torque this organelle can exert to turn a microbe. + MovementOrganelle(float momentum, float torque){ + + // Store this here temporarily + this.force = Float3(momentum); + this.torque = torque; + } + + void + onAddedToMicrobe( + ObjectID microbeEntity, + int q, int r, int rotation, + PlacedOrganelle@ organelle + ) override { + + this.force = calculateForce(q, r, this.force.X); + + Float3 organellePos = Hex::axialToCartesian(q, r); + Float3 nucleus = Hex::axialToCartesian(0, 0); + auto delta = nucleus - organellePos; + float angle = atan2(-delta.Z, delta.X); + if(angle < 0){ + angle = angle + (2 * PI); + } + + angle = ((angle * 180)/PI + 180) % 360; + + // This is already added by the PlacedOrganlle.onAddedToMicrobe + Model@ model = organelle.world.GetComponent_Model(organelle.organelleEntity); + + if(model is null) + assert(false, "MovementOrganelle added to Organelle that has no Model component"); + + // The organelles' scenenode is positioned by itself unlike + // the lua version where that was also attempted here + + // Create animation component + Animated@ animated = organelle.world.Create_Animated(organelle.organelleEntity, + model.GraphicalObject); + SimpleAnimation moveAnimation("Move"); + moveAnimation.Loop = true; + // 0.25 is the "idle" animation speed when the flagellum isn't used + moveAnimation.SpeedFactor = 0.25f; + animated.AddAnimation(moveAnimation); + // Don't forget to mark to apply the new animation + animated.Marked = true; + + + auto@ renderNode = organelle.world.GetComponent_RenderNode(organelle.organelleEntity); + renderNode.Node.setPosition(organellePos); + renderNode.Node.setOrientation(Ogre::Quaternion(Ogre::Degree(angle), + Ogre::Vector3(0, 1, 0))); + } + + // void MovementOrganelle.load(storage){ + // this.position = {} + // this.energyMultiplier = storage.get("energyMultiplier", 0.025) + // this.force = storage.get("force", Vector3(0,0,0)) + // this.torque = storage.get("torque", 500) + // } + + // void MovementOrganelle.storage(){ + // auto storage = StorageContainer() + // storage.set("energyMultiplier", this.energyMultiplier) + // storage.set("force", this.force) + // storage.set("torque", this.torque) + // return storage + // } + + private void _moveMicrobe(ObjectID microbeEntity, PlacedOrganelle@ organelle, + int milliseconds, MicrobeComponent@ microbeComponent, Physics@ rigidBodyComponent, + Position@ pos + ) { + // The movementDirection is the player or AI input + Float3 direction = microbeComponent.movementDirection; + + // For changing animation speed + Animated@ animated = organelle.world.GetComponent_Animated(organelle.organelleEntity); + + auto forceMagnitude = this.force.Dot(direction); + if(forceMagnitude > 0){ + if(direction.LengthSquared() < EPSILON || this.force.LengthSquared() < EPSILON){ + this.movingTail = false; + animated.GetAnimation(0).SpeedFactor = 0.25f; + return; + } + + this.movingTail = true; + animated.GetAnimation(0).SpeedFactor = 1.3; + + auto energy = abs(this.energyMultiplier * forceMagnitude * milliseconds / 1000.f); + auto availableEnergy = MicrobeOperations::takeCompound(organelle.world, + microbeEntity, SimulationParameters::compoundRegistry().getTypeId("atp"), + energy); + + if(availableEnergy < energy){ + forceMagnitude = sign(forceMagnitude) * availableEnergy * 1000.f / + milliseconds / this.energyMultiplier; + this.movingTail = false; + animated.GetAnimation(0).SpeedFactor = 0.25f; + } + float impulseMagnitude = microbeComponent.movementFactor * milliseconds * + forceMagnitude / 1000.f; + + // Rotate the 'thrust' based on our orientation + direction = pos._Orientation.RotateVector(direction); + + // This isn't needed + //direction.Y = 0; + //direction = direction.Normalize(); + Float3 impulse = direction * impulseMagnitude; + rigidBodyComponent.GiveImpulse(impulse, pos._Position); + } else { + if(this.movingTail){ + this.movingTail = false; + animated.GetAnimation(0).SpeedFactor = 0.25f; + } + } + } + + void _turnMicrobe(ObjectID microbeEntity, PlacedOrganelle@ organelle, int logicTime, + MicrobeComponent@ microbeComponent, Physics@ rigidBodyComponent, Position@ pos){ + + if(this.torque == 0){ + return; + } + + const auto target = Float4::QuaternionLookAt(pos._Position, + microbeComponent.facingTargetPoint); + const auto current = pos._Orientation; + // Slerp 50% of the way each call + const auto interpolated = current.Slerp(target, 0.5f); + // const auto interpolated = target; + + // Not sure if updating the Position component here does anything + pos._Orientation = interpolated; + pos.Marked = true; + + // LOG_WRITE("turn = " + pos._Orientation.X + ", " + pos._Orientation.Y + ", " + // + pos._Orientation.Z + ", " + pos._Orientation.W); + + rigidBodyComponent.SetOnlyOrientation(interpolated); + return; + + // auto targetDirection = microbeComponent.facingTargetPoint - pos._Position; + // // TODO: direct multiplication was also used here + // // Float3 localTargetDirection = pos._Orientation.Inverse().RotateVector(targetDirection); + // Float3 localTargetDirection = pos._Orientation.Inverse().RotateVector(targetDirection); + + // // Float3 localTargetDirection = pos._Orientation.ToAxis() - targetDirection; + // // localTargetDirection.Y = 0; // improper fix. facingTargetPoint somehow gets a non-zero y value. + // LOG_WRITE("local direction = " + localTargetDirection.X + ", " + + // localTargetDirection.Y + ", " + localTargetDirection.Z); + + // assert(localTargetDirection.Y < 0.01, + // "Microbes should only move in the 2D plane with y = 0"); + + // // This doesn't help with the major jitter + // // // Round to zero if either is too small + // // if(abs(localTargetDirection.X) < 0.01) + // // localTargetDirection.X = 0; + // // if(abs(localTargetDirection.Z) < 0.01) + // // localTargetDirection.Z = 0; + + // float alpha = atan2(-localTargetDirection.X, -localTargetDirection.Z); + // float absAlpha = abs(alpha) * RADIANS_TO_DEGREES; + // microbeComponent.microbetargetdirection = absAlpha; + // if(absAlpha > 1){ + + // LOG_WRITE("Alpha is: " + alpha); + // Float3 torqueForces = Float3(0, this.torque * alpha * logicTime * + // microbeComponent.movementFactor * 0.00001f, 0); + // rigidBodyComponent.AddOmega(torqueForces); + + // // Rotation is the same for each flagella so doing this + // // makes things less likely to break and still work. Only + // // tweak should be that there should be + // // microbeComponent.movementFactor alternative for + // // rotation that depends on flagella and cilia. The + // // problem with this is that there are weird spots where + // // this gets stuck at (hopefully works better with the + // // rounding of X and Z) + // // Float3 torqueForces = Float3(0, this.torque * alpha * logicTime * + // // microbeComponent.movementFactor * 0.0001f, 0); + // // rigidBodyComponent.SetOmega(torqueForces); + + // } else { + // // Doesn't work + // // // Slow down rotation if there is some + // // auto omega = rigidBodyComponent.GetOmega(); + // // rigidBodyComponent.SetOmega(Float3(0, 0, 0)); + + // // if(abs(omega.X) > 1 || abs(omega.Z) > 1){ + + // // rigidBodyComponent.AddOmega(Float3(-omega.X * 0.01f, 0, -omega.Z * 0.01f)); + // // } + // } + } + + void + update( + ObjectID microbeEntity, + PlacedOrganelle@ organelle, + int logicTime + ) override { + + // TODO: what does this code attempt to do. Don't we already set the organelle's + // scenenode to the right position already (in PlacedOrganelle.onAddedToMicrobe)? + // The point of this is to make it auto-update when the membrane changes shape probably. + // auto membraneComponent = getComponent(microbeEntity, MembraneComponent); + // local x, y = axialToCartesian(organelle.position.q, organelle.position.r); + // auto membraneCoords = membraneComponent.getExternOrganellePos(x, y); + // auto translation = Vector3(membraneCoords[1], membraneCoords[2], 0); + // this.sceneNode.transform.position = translation; + // this.sceneNode.transform.touch(); + + MicrobeComponent@ microbeComponent = cast( + organelle.world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto rigidBodyComponent = organelle.world.GetComponent_Physics(microbeEntity); + auto pos = organelle.world.GetComponent_Position(microbeEntity); + + if(rigidBodyComponent.Body is null){ + + LOG_WARNING("Skipping movement organelle update for microbe without physics body"); + return; + } + + _turnMicrobe(microbeEntity, organelle, logicTime, microbeComponent, + rigidBodyComponent, pos); + _moveMicrobe(microbeEntity, organelle, logicTime, microbeComponent, + rigidBodyComponent, pos); + } + + private Float3 force; + private float torque; + float energyMultiplier = 0.025; + // float backwards_multiplier = 0; + private bool movingTail = false; +} diff --git a/scripts/microbe_stage/movement_organelle.lua b/scripts/microbe_stage/movement_organelle.lua deleted file mode 100644 index 065448f2de0..00000000000 --- a/scripts/microbe_stage/movement_organelle.lua +++ /dev/null @@ -1,168 +0,0 @@ --- Enables a microbe to move and turn - --- See organelle_component.lua for more information about the --- organelle component methods and the arguments they receive. - --- Calculate the momentum of the movement organelle based on angle towards nucleus -local function calculateForce(q, r, momentum) - local organelleX, organelleY = axialToCartesian(q, r) - local nucleusX, nucleusY = axialToCartesian(0, 0) - local deltaX = nucleusX - organelleX - local deltaY = nucleusY - organelleY - local dist = math.sqrt(deltaX^2 + deltaY^2) -- For normalizing vector - local momentumX = deltaX / dist * momentum - local momentumY = deltaY / dist * momentum - local force = Vector3(momentumX, momentumY, 0.0) - return force - -end - -MovementOrganelle = class( - OrganelleComponent, - -- Constructor - -- - -- @param arguments.momentum - -- The force this organelle can exert to move a microbe. - -- - -- @param arguments.torque - -- The torque this organelle can exert to turn a microbe. - function(self, arguments, data) - OrganelleComponent.create(self, arguments, data) - - --making sure this doesn't run when load() is called - if arguments == nil and data == nil then - return - end - - self.energyMultiplier = 0.025 - self.force = calculateForce(data.q, data.r, arguments.momentum) - self.torque = arguments.torque - self.backwards_multiplier = 0 - self.x = 0 - self.y = 0 - self.angle = 0 - self.movingTail = false - end -) - -function MovementOrganelle:onAddedToMicrobe(microbeEntity, q, r, rotation, organelle) - local organelleX, organelleY = axialToCartesian(q, r) - local nucleusX, nucleusY = axialToCartesian(0, 0) - local deltaX = nucleusX - organelleX - local deltaY = nucleusY - organelleY - local angle = math.atan2(deltaY, deltaX) - if (angle < 0) then - angle = angle + 2*math.pi - end - angle = (angle * 180/math.pi + 180) % 360 - - self.sceneNode = organelle.sceneNode - self.sceneNode.transform.orientation = Quaternion.new(Radian.new(Degree(angle)), Vector3(0, 0, 1)) - self.sceneNode.transform.position = organelle.position.cartesian - self.sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) - self.sceneNode.transform:touch() - self.sceneNode.parent = microbeEntity - -- self.sceneNode is a nullptr because it is already added to an entity - --organelle.organelleEntity:addComponent(self.sceneNode) - - self.sceneNode:playAnimation("Move", true) - self.sceneNode:setAnimationSpeed(0.25) - - --Adding a mesh to the organelle. - local mesh = organelleTable[organelle.name].mesh - if mesh ~= nil then - self.sceneNode.meshName = mesh - end -end - -function MovementOrganelle:load(storage) - self.position = {} - self.energyMultiplier = storage:get("energyMultiplier", 0.025) - self.force = storage:get("force", Vector3(0,0,0)) - self.torque = storage:get("torque", 500) -end - -function MovementOrganelle:storage() - local storage = StorageContainer.new() - storage:set("energyMultiplier", self.energyMultiplier) - storage:set("force", self.force) - storage:set("torque", self.torque) - return storage -end - -function MovementOrganelle:_moveMicrobe(microbeEntity, milliseconds) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - local sceneNodeComponent = getComponent(microbeEntity, OgreSceneNodeComponent) - - local direction = microbeComponent.movementDirection - - local forceMagnitude = self.force:dotProduct(direction) - if forceMagnitude > 0 then - if direction:isZeroLength() or self.force:isZeroLength() then - self.movingTail = false - self.sceneNode:setAnimationSpeed(0.25) - return - end - self.movingTail = true - self.sceneNode:setAnimationSpeed(1.3) - - local energy = math.abs(self.energyMultiplier * forceMagnitude * milliseconds / 1000) - local availableEnergy = MicrobeSystem.takeCompound(microbeEntity, CompoundRegistry.getCompoundId("atp"), energy) - if availableEnergy < energy then - forceMagnitude = sign(forceMagnitude) * availableEnergy * 1000 / milliseconds / self.energyMultiplier - self.movingTail = false - self.sceneNode:setAnimationSpeed(0.25) - end - local impulseMagnitude = microbeComponent.movementFactor * milliseconds * forceMagnitude / 1000 - - local impulse = impulseMagnitude * direction - local a = sceneNodeComponent.transform.orientation * impulse - rigidBodyComponent:applyCentralImpulse( - sceneNodeComponent.transform.orientation * impulse - ) - else - if self.movingTail then - self.movingTail = false - self.sceneNode:setAnimationSpeed(0.25) - end - end -end - --- TODO: Add logictime considerations. -function MovementOrganelle:_turnMicrobe(microbeEntity) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - local sceneNodeComponent = getComponent(microbeEntity, OgreSceneNodeComponent) - - if self.torque == 0 then - return - end - local transform = sceneNodeComponent.transform - local targetDirection = microbeComponent.facingTargetPoint - transform.position - local localTargetDirection = transform.orientation:Inverse() * targetDirection - localTargetDirection.z = 0 -- improper fix. facingTargetPoint somehow gets a non-zero z value. - assert(localTargetDirection.z < 0.01, "Microbes should only move in the 2D plane with z = 0") - local alpha = math.atan2( - -localTargetDirection.x, - localTargetDirection.y - ) - microbeComponent.microbetargetdirection = math.abs(math.deg(alpha)) - if math.abs(math.deg(alpha)) > 1 then - rigidBodyComponent:applyTorque( - Vector3(0, 0, self.torque * alpha * microbeComponent.movementFactor) - ) - end -end - -function MovementOrganelle:update(microbeEntity, organelle, logicTime) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - local x, y = axialToCartesian(organelle.position.q, organelle.position.r) - local membraneCoords = membraneComponent:getExternOrganellePos(x, y) - local translation = Vector3(membraneCoords[1], membraneCoords[2], 0) - self.sceneNode.transform.position = translation - self.sceneNode.transform:touch() - - self:_turnMicrobe(microbeEntity) - self:_moveMicrobe(microbeEntity, logicTime) -end diff --git a/scripts/microbe_stage/nucleus_organelle.as b/scripts/microbe_stage/nucleus_organelle.as new file mode 100644 index 00000000000..fd7bd052986 --- /dev/null +++ b/scripts/microbe_stage/nucleus_organelle.as @@ -0,0 +1,106 @@ +#include "organelle_component.as" +#include "microbe_operations.as" + +//////////////////////////////////////////////////////////////////////////////// +// Class for the single core organelle of any microbe +//////////////////////////////////////////////////////////////////////////////// +class NucleusOrganelle : OrganelleComponent{ + // Constructor + NucleusOrganelle(){ + + // Moved to onAddedToMicrobe + } + + // Overridded from OrganelleComponent.onAddedToMicrobe + void + onAddedToMicrobe( + ObjectID microbeEntity, + int q, int r, int rotation, + PlacedOrganelle@ organelle + ) override { + + auto world = organelle.world; + auto microbeNode = world.GetComponent_RenderNode(microbeEntity); + auto speciesComponent = MicrobeOperations::getSpeciesComponent(world, microbeEntity); + + assert(microbeNode !is null, "microbe entity has no RenderNode"); + + golgi = world.CreateEntity(); + ER = world.CreateEntity(); + + auto sceneNode1 = world.Create_RenderNode(golgi); + auto model1 = world.Create_Model(golgi, sceneNode1.Node, "golgi.mesh"); + + // Tint must be set + model1.GraphicalObject.setCustomParameter(1, Ogre::Vector4(speciesComponent.colour)); + + sceneNode1.Scale = Float3(HEX_SIZE, HEX_SIZE, HEX_SIZE); + sceneNode1.Node.setPosition(Hex::axialToCartesian(q + 1, r + 1)); + //sceneNode1.Node.setOrientation(Ogre::Quaternion(Ogre::Radian(rotation), + // Ogre::Vector3(0, .5, 1))); + sceneNode1.Node.setOrientation(Ogre::Quaternion(Ogre::Degree(rotation), + Ogre::Vector3(0, 1, -1))); + sceneNode1.Marked = true; + + sceneNode1.Node.removeFromParent(); + microbeNode.Node.addChild(sceneNode1.Node); + + world.SetEntitysParent(microbeEntity, golgi); + + auto sceneNode2 = world.Create_RenderNode(ER); + auto model2 = world.Create_Model(ER, sceneNode2.Node, "ER.mesh"); + + // Tint must be set + model2.GraphicalObject.setCustomParameter(1, Ogre::Vector4(speciesComponent.colour)); + + sceneNode2.Scale = Float3(HEX_SIZE, HEX_SIZE, HEX_SIZE); + sceneNode2.Node.setPosition(Hex::axialToCartesian(q, r+.4)); + + sceneNode2.Node.setOrientation(Ogre::Quaternion(Ogre::Degree(rotation+10), + Ogre::Vector3(0, 1, -1))); + sceneNode2.Marked = true; + + sceneNode2.Node.removeFromParent(); + microbeNode.Node.addChild(sceneNode2.Node); + + world.SetEntitysParent(microbeEntity, ER); + + + // This does nothing... + // auto speciesColour = speciesComponent.colour; + // this.colourSuffix = "" + floor(speciesColour.X * 256) + + // floor(speciesColour.Y * 256) + floor(speciesColour.Z * 256); + + organelle._needsColourUpdate = true; + } + + // Overridded from OrganelleComponent.onRemovedFromMicrobe + void + onRemovedFromMicrobe( + ObjectID microbeEntity, + PlacedOrganelle@ organelle + ) override { + + auto world = organelle.world; + + world.QueueDestroyEntity(golgi); + world.QueueDestroyEntity(ER); + golgi = NULL_OBJECT; + ER = NULL_OBJECT; + } + + // void NucleusOrganelle.storage(){ + // return StorageContainer() + // } + + // void NucleusOrganelle.load(storage){ + // this.golgi = Entity(g_luaEngine.currentGameState.wrapper) + // this.ER = Entity(g_luaEngine.currentGameState.wrapper) + // } + + private ObjectID golgi = NULL_OBJECT; + private ObjectID ER = NULL_OBJECT; + //! Not sure if this is used for anything + private string colourSuffix; +} + diff --git a/scripts/microbe_stage/nucleus_organelle.lua b/scripts/microbe_stage/nucleus_organelle.lua deleted file mode 100644 index 3088f489c07..00000000000 --- a/scripts/microbe_stage/nucleus_organelle.lua +++ /dev/null @@ -1,94 +0,0 @@ --------------------------------------------------------------------------------- --- Class for the single core organelle of any microbe --------------------------------------------------------------------------------- -NucleusOrganelle = class( - OrganelleComponent, - -- Constructor - function(self, arguments, data) - OrganelleComponent.create(self, arguments, data) - - --making sure this doesn't run when load() is called - if arguments == nil and data == nil then - return - end - - self.golgi = Entity.new(g_luaEngine.currentGameState.wrapper) - self.ER = Entity.new(g_luaEngine.currentGameState.wrapper) - end -) - --- See organelle_component.lua for more information about the --- organelle component methods and the arguments they receive. - - --- Overridded from Organelle:onAddedToMicrobe -function NucleusOrganelle:onAddedToMicrobe(microbeEntity, q, r, rotation, organelle) - local x, y = axialToCartesian(q-1, r-1) - local sceneNode1 = OgreSceneNodeComponent.new() - sceneNode1.meshName = "golgi.mesh" - sceneNode1.transform.position = Vector3(x,y,0) - sceneNode1.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) - sceneNode1.transform.orientation = Quaternion.new(Radian.new(Degree(rotation)), - Vector3(0, 0, 1)) - sceneNode1.transform:touch() - sceneNode1.parent = microbeEntity - microbeEntity:addChild(self.golgi) - self.golgi:addComponent(sceneNode1) - self.golgi_sceneNode = sceneNode1 - self.golgi:setVolatile(true) - - local sceneNode2 = OgreSceneNodeComponent.new() - sceneNode2.meshName = "ER.mesh" - sceneNode2.transform.position = Vector3(0,0,0) - sceneNode2.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) - sceneNode2.transform.orientation = Quaternion.new(Radian.new(Degree(rotation+10)), - Vector3(0, 0, 1)) - sceneNode2.transform:touch() - sceneNode2.parent = microbeEntity - microbeEntity:addChild(self.ER) - self.ER:addComponent(sceneNode2) - self.ER_sceneNode = sceneNode2 - self.ER:setVolatile(true) - - self.sceneNode = organelle.sceneNode - - -- If we are not in the editor, get the color of this species. - if MicrobeSystem.getSpeciesComponent(microbeEntity) ~= nil then - local speciesColour = MicrobeSystem.getSpeciesComponent(microbeEntity).colour - self.colourSuffix = "" .. math.floor(speciesColour.x * 256) .. math.floor(speciesColour.y * 256) .. math.floor(speciesColour.z * 256) - end - - self._needsColourUpdate = true -end - -function NucleusOrganelle:onRemovedFromMicrobe(microbeEntity, q, r) - self.golgi:destroy() - self.ER:destroy() -end - -function NucleusOrganelle:storage() - return StorageContainer.new() -end - -function NucleusOrganelle:load(storage) - self.golgi = Entity.new(g_luaEngine.currentGameState.wrapper) - self.ER = Entity.new(g_luaEngine.currentGameState.wrapper) -end - --- This function isn't called anywhere. -function NucleusOrganelle:updateColour(organelle) - -- Update the colours of the additional organelle models. - --[[if self.sceneNode.entity ~= nil and self.golgi.sceneNode.entity ~= nil then - --print(organelle.colour.r .. ", " .. organelle.colour.g .. ", " .. organelle.colour.b) - - local entity = self.sceneNode.entity - local golgiEntity = self.golgi.sceneNode.entity - local ER_entity = self.ER.sceneNode.entity - - entity:tintColour("nucleus", organelle.colour) - golgiEntity:tintColour("golgi", organelle.colour) - ER_entity:tintColour("ER", organelle.colour) - - organelle._needsColourUpdate = false - end]] -end diff --git a/scripts/microbe_stage/organelle.as b/scripts/microbe_stage/organelle.as new file mode 100644 index 00000000000..2d52dd53ab4 --- /dev/null +++ b/scripts/microbe_stage/organelle.as @@ -0,0 +1,1065 @@ +#include "microbe.as" +#include "hex.as" + +// How fast organelles grow. +const auto GROWTH_SPEED_MULTILPIER = 0.5f / 1000; + +// Percentage of the compounds that compose the organelle released +// upon death (between 0.0 and 1.0). +const auto COMPOUND_RELEASE_PERCENTAGE = 0.3f; + + +//! \todo Replace with Int2 +class Hex{ + + Hex(int q, int r){ + this.q = q; + this.r = r; + } + + int q; + int r; +} + +//! Class that is given a definition of organelle and it represents its data +//! \note Before there was an instance of this class for each microbe. Now this is global and +//! each microbe has a PlacedOrganelle instance instead (which also has many properties +//! that this class used to have) +class Organelle{ + + Organelle(const OrganelleParameters &in parameters){ + + _name = parameters.name; + mass = parameters.mass; + mesh = parameters.mesh; + gene = parameters.gene; + chanceToCreate = parameters.chanceToCreate; + + initialComposition = parameters.initialComposition; + components = parameters.components; + processes = parameters.processes; + + // Sanity check processes // + for(uint i = 0; i < processes.length(); ++i){ + + if(processes[i] is null){ + + assert(false, "Organelle created with null process at index: " + i); + } + } + + // Add hexes // + for(uint i = 0; i < parameters.hexes.length(); ++i){ + + addHex(parameters.hexes[i].X, parameters.hexes[i].Y); + } + + // Calculate organelleCost and compoundsLeft// + // This method sets organelleCost + calculateCost(initialComposition); + } + + ~Organelle(){ + + } + + protected void calculateCost(dictionary composition){ + + organelleCost = 0; + + auto keys = composition.getKeys(); + + for(uint i = 0; i < keys.length(); ++i){ + + const auto compoundName = keys[i]; + int amount; + + if(!composition.get(keys[i], amount)){ + + LOG_ERROR("Invalid value in calculateCost composition"); + continue; + } + + // compoundsLeft[compoundName] = amount; + initialComposition[compoundName] = amount; + organelleCost += amount; + } + } + + // Adds a hex to this organelle + // + // @param q, r + // Axial coordinates of the new hex + // + // @returns success + // True if the hex could be added, false if there already is a hex at (q,r) + // @note This needs to be done only once when this class is instantiated + protected bool addHex(int q, int r){ + int64 s = Hex::encodeAxial(q, r); + if(hexes.exists(formatInt(s))) + return false; + + Hex@ hex = Hex(q, r); + + @hexes[formatInt(s)] = hex; + return true; + } + + // Retrieves a hex + // + // @param q, r + // Axial coordinates of the hex + // + // @returns hex + // The hex at (q, r) or nil if there's no hex at that position + Hex@ getHex(int q, int r) const{ + int64 s = Hex::encodeAxial(q, r); + Hex@ hex; + + if(hexes.get(formatInt(s), @hex)) + return hex; + return null; + } + + array@ getHexes() const{ + + array@ result = array(); + + auto keys = hexes.getKeys(); + for(uint i = 0; i < keys.length(); ++i){ + + result.insertLast(cast(hexes[keys[i]])); + } + + return result; + } + + //! \returns The hexes but rotated (rotation degrees) + //! \todo Should this and the normal getHexes return handles to arrays + array@ getRotatedHexes(int rotation) const{ + + array@ result = array(); + + int times = rotation / 60; + + auto keys = hexes.getKeys(); + for(uint i = 0; i < keys.length(); ++i){ + + Hex@ hex = cast(hexes[keys[i]]); + + auto rotated = Hex::rotateAxialNTimes({hex.q, hex.r}, times); + result.insertLast(Hex(rotated.X, rotated.Y)); + } + + return result; + } + + Float3 calculateCenterOffset() const{ + int count = 0; + + Float3 offset = Float3(0, 0, 0); + + auto keys = hexes.getKeys(); + for(uint i = 0; i < keys.length(); ++i){ + + ++count; + + auto hex = cast(hexes[keys[i]]); + offset += Hex::axialToCartesian(hex.q, hex.r); + } + + offset /= count; + return offset; + } + + // // Removes a hex from this organelle + // // + // // @param q,r + // // Axial coordinates of the hex to remove + // // + // // @returns success + // // True if the hex could be removed, false if there's no hex at (q,r) + // function Organelle.removeHex(q, r) + // assert(not self.microbeEntity, "Cannot change organelle shape while it is in a microbe") + // local s = encodeAxial(q, r) + // local hex = table.remove(self._hexes, s) + // if hex { + // self.collisionShape.removeChildShape(hex.collisionShape) + // return true + // else + // return false + // } + // } + + bool hasComponent(const string &in name) const{ + + for(uint i = 0; i < components.length(); ++i){ + if(components[i].name == name) + return true; + } + + return false; + } + + // ------------------------------------ // + + // Prevent modification + string name { + + get const{ + return _name; + } + } + + private string _name; + float mass; + string gene; + + array components; + private dictionary hexes; + + // The initial amount of compounds this organelle consists of + dictionary initialComposition; + + // The names in the processes need to match the ones in bioProcessRegistry + // Or better yet, be loaded from the registry that reads the json files + // so that the processes can be configured that way + array processes; + + // The total number of compounds we need before we can split. + int organelleCost; + + // Name of the model used for this organelle. For example "nucleus.mesh" + string mesh; + + //! Chance of randomly generating this (used by procedural_microbes.as) + float chanceToCreate = 0.0; +} + +enum ORGANELLE_HEALTH{ + DEAD = 0, + ALIVE = 1, + // Organelle is ready to divide + CAN_DIVIDE = 2 +}; + +//! These are placed either on an actual microbe where they are +//! onAddedToMicrobe() OR on templates where these just have positions +//! set and should be duplicated for the purpose of adding to a +//! microbe +class PlacedOrganelle : SpeciesStoredOrganelleType{ + + PlacedOrganelle(Organelle@ organelle, int q, int r, int rotation){ + + @this._organelle = organelle; + this.q = q; + this.r = r; + this.rotation = rotation; + + _commonConstructor(); + } + + //! Takes type from another PlacedOrganelle + PlacedOrganelle(PlacedOrganelle@ typefromother, int q, int r, int rotation){ + + @this._organelle = typefromother._organelle; + this.q = q; + this.r = r; + this.rotation = rotation; + + _commonConstructor(); + } + + //! Takes everything that's sensible to copy from another PlacedOrganelle + PlacedOrganelle(PlacedOrganelle@ other){ + + @this._organelle = other._organelle; + this.q = other.q; + this.r = other.r; + this.rotation = other.rotation; + + _commonConstructor(); + } + + ~PlacedOrganelle(){ + + if(microbeEntity != NULL_OBJECT){ + + LOG_ERROR("PlacedOrganelle (" + organelle.name + ") not removed from microbe " + "before it was destroyed, microbe: " + microbeEntity); + } + } + + private void _commonConstructor(){ + + // Sanity check + if(_organelle is null) + assert(false, "PlacedOrganelle created with null Organelle"); + + resetHealth(); + + // Create instances of components // + for(uint i = 0; i < organelle.components.length(); ++i){ + + components.insertLast(organelle.components[i].factory()); + } + + compoundsLeft = organelle.initialComposition; + } + + void resetHealth(){ + + // Copy // + composition = _organelle.initialComposition; + } + + + // Called by Microbe.update + // + // Override this to make your organelle class do something at regular intervals + // + // @param logicTime + // The time since the last call to update() + void update(int logicTime){ + if(flashDuration >= 0){ + + flashDuration -= logicTime; + // Use organelle.world to get the MicrobeSystem + Float4 speciesColour = MicrobeOperations::getSpeciesComponent(world, + microbeEntity).colour; + + Float4 colour; + + // How frequent it flashes, would be nice to update the + // flash function to have this variable + if(flashDuration % 600 < 300){ + + colour = flashColour; + + } else { + colour = speciesColour; + } + + if(flashDuration <= 0){ + flashDuration = 0; + colour = speciesColour; + } + + // TODO: this needs a separate colour property + flashColour = colour; + _needsColourUpdate = true; + } + + // If the organelle is supposed to be another color. + if(_needsColourUpdate){ + // This method doesn't actually apply the colour so I have + // no clue how the flashing works + updateColour(); + } + + // Update each OrganelleComponent + for(uint i = 0; i < components.length(); ++i){ + components[i].update(microbeEntity, this, logicTime); + } + } + + protected Float4 calculateHSLForOrganelle(Float4 oldColour) + { + //get hue satraution and brightness for the colour + Ogre::Real saturation = 0; + Ogre::Real brightness = 0; + Ogre::Real hue = 0; + + //convert from float to colour + Ogre::ColourValue newColour = Ogre::ColourValue(oldColour); + + + newColour.getHSB(hue, saturation, brightness); + newColour.setHSB(hue, saturation*2, brightness); + + //return the new colour as a float4 + return Float4(newColour); + } + + protected void updateColour(){ + + if(organelleEntity == NULL_OBJECT || microbeEntity == NULL_OBJECT) + return; + + auto model = world.GetComponent_Model(organelleEntity); + + if(model !is null){ + + // TODO: clean up this check + if(organelle.mesh != "flagellum.mesh"){ + + this.colourTint = calculateHSLForOrganelle(this.colourTint); + this.flashColour = calculateHSLForOrganelle(this.flashColour); + + model.GraphicalObject.setCustomParameter(1, + Ogre::Vector4( this.colourTint * this.flashColour) + ); + } + } + + _needsColourUpdate = false; + } + + // Returns the meaning of compoundBin value + ORGANELLE_HEALTH getHealth(){ + if(compoundBin <= ORGANELLE_HEALTH::DEAD) + return ORGANELLE_HEALTH::DEAD; + if(compoundBin < ORGANELLE_HEALTH::CAN_DIVIDE) + return ORGANELLE_HEALTH::ALIVE; + return ORGANELLE_HEALTH::CAN_DIVIDE; + } + + //! \returns compoundBin + float getCompoundBin(){ + return compoundBin; + } + + // Gives organelles more compounds + void growOrganelle(CompoundBagComponent@ compoundBagComponent, int logicTime){ + // Finds the total number of needed compounds. + float sum = 0.0; + + auto compoundKeys = compoundsLeft.getKeys(); + for(uint i = 0; i < compoundKeys.length(); ++i){ + + // Finds which compounds the cell currently has. + if(compoundBagComponent.getCompoundAmount( + SimulationParameters::compoundRegistry().getTypeId(compoundKeys[i])) >= 1) + { + float amount; + if(!compoundsLeft.get(compoundKeys[i], amount)){ + + LOG_ERROR("Invalid type in compoundsLeft"); + continue; + } + + sum += amount; + } + } + + // If sum is 0, we either have no compounds, in which case we + // cannot grow the organelle, or the organelle is ready to + // split (i.e. compoundBin = 2), in which case we wait for the + // microbe to handle the split. + if(sum <= 0.0) + return; + + // Randomly choose which of the compounds are used in reproduction. + // Uses a roulette selection. + float id = GetEngine().GetRandom().GetFloat(0, 1) * sum; + + for(uint i = 0; i < compoundKeys.length(); ++i){ + + const auto compoundName = compoundKeys[i]; + + float amount; + if(!compoundsLeft.get(compoundName, amount)){ + + LOG_ERROR("Invalid type in compoundsLeft"); + continue; + } + + if(id - amount < 0){ + + // The random number is from this compound, so attempt to take it. + float amountToTake = min(logicTime * GROWTH_SPEED_MULTILPIER, amount); + amountToTake = compoundBagComponent.takeCompound( + SimulationParameters::compoundRegistry().getTypeId(compoundName), + amountToTake); + compoundsLeft[compoundName] = float(compoundsLeft[compoundName]) - + amountToTake; + break; + + } else { + id -= amount; + } + } + + // Calculate the new growth value. + recalculateBin(); + } + + void damageOrganelle(float damageAmount){ + // Flash the organelle that was damaged. + flashOrganelle(3000, Float4(1, 0.2, 0.2, 1)); + + // Calculate the total number of compounds we need + // to divide now, so that we can keep this ratio. + const float totalLeft = calculateCompoundsLeft(); + + // Calculate how much compounds the organelle needs to have + // to result in a health equal to compoundBin - amount. + const float damageFactor = (2.0 - compoundBin + damageAmount) * + (organelle.organelleCost / totalLeft); + + scaleCompoundsLeft(damageFactor); + + recalculateBin(); + } + + private void scaleCompoundsLeft(float scaleFactor){ + + auto compoundKeys = compoundsLeft.getKeys(); + for(uint i = 0; i < compoundKeys.length(); ++i){ + float amount; + if(!compoundsLeft.get(compoundKeys[i], amount)){ + + LOG_ERROR("Invalid type in compoundsLeft"); + continue; + } + + compoundsLeft[compoundKeys[i]] = amount * scaleFactor; + } + } + + // Calculates total number of compounds left until this organelle can divide + float calculateCompoundsLeft() const{ + + float totalLeft = 0; + + auto compoundKeys = compoundsLeft.getKeys(); + for(uint i = 0; i < compoundKeys.length(); ++i){ + + float amount; + if(!compoundsLeft.get(compoundKeys[i], amount)){ + + LOG_ERROR("Invalid type in compoundsLeft"); + continue; + } + + totalLeft += amount; + } + + return totalLeft; + } + + private void recalculateBin(){ + // Calculate the new growth growth + float totalCompoundsLeft = calculateCompoundsLeft(); + + compoundBin = 2.0 - totalCompoundsLeft / organelle.organelleCost; + + // If the organelle is damaged... + if(compoundBin < 1.0){ + // If it is dead + if(compoundBin <= 0.0){ + // If it was split from a primary organelle, destroy it. + if(isDuplicate == true){ + + // Calls different method for possible sound and effects + MicrobeOperations::organelleDestroyedByDamage(world, + microbeEntity, {q, r}); + + // Notify the organelle the sister organelle it is no longer split. + sisterOrganelle.wasSplit = false; + return; + + } else { + // If it is a primary organelle, make sure that + // it's compound bin is not less than 0. + compoundBin = 0.0; + + scaleCompoundsLeft(2); + } + } + + // Scale the model at a slower rate (so that 0.0 is half size). + // Nucleus isn't scaled + // TODO: This isn't the cheapest call so maybe this should be cached + if(!organelle.hasComponent("NucleusOrganelle")){ + + RenderNode@ sceneNode = world.GetComponent_RenderNode( + organelleEntity); + + sceneNode.Scale = Float3((1.0 + compoundBin)/2, + (1.0 + compoundBin)/2, + (1.0 + compoundBin)/2) * HEX_SIZE; + sceneNode.Marked = true; + } + + // See update and updateColour for as to why this doesn't work + // Darken the color. Will be updated on next call of update() + colourTint = Float4((1.0 + compoundBin)/2, compoundBin, compoundBin, 1); + _needsColourUpdate = true; + + } else{ + // Scale the organelle model to reflect the new size. + // Only if it is different + const Float3 newScale = Float3(compoundBin, compoundBin, compoundBin) * HEX_SIZE; + + RenderNode@ sceneNode = world.GetComponent_RenderNode( + organelleEntity); + + if(newScale != sceneNode.Scale){ + + sceneNode.Scale = newScale; + sceneNode.Marked = true; + } + } + } + + // Resets the state. Used after dividing? + void reset(){ + // Return the compound bin to its original state + this.compoundBin = 1.0; + + // Assign (doesn't only copy a reference) + compoundsLeft = organelle.initialComposition; + + // Scale the organelle model to reflect the new size. + // This might be able to be skipped as the recalculateBin method will always set + // the correct scale + RenderNode@ sceneNode = world.GetComponent_RenderNode( + organelleEntity); + + sceneNode.Scale = Float3(1, 1, 1) * HEX_SIZE; + sceneNode.Marked = true; + + // If it was split from a primary organelle, destroy it. + if(isDuplicate){ + MicrobeOperations::removeOrganelle(world, microbeEntity, + {this.q, this.r}); + } else { + wasSplit = false; + } + } + + + // // Is this used? This will be quite difficult to do afterwards the Organelle + // // creates its collision (could be handled by a flag to onAddedToMicrobe to not + // // create physics + // function Organelle.removePhysics() + // this.collisionShape.clear() + // } + + + // Called by a microbe when this organelle has been added to it + // + // @param microbe + // The organelle's new owner + // + // @param q, r + // Axial coordinates of the organelle's center + // @param world + // the world the microbe entity is in. This is used to retrieve various components + // @note This is quite an expensive method as this creates a new entity with + // multiple components + void onAddedToMicrobe(ObjectID microbe, CellStageWorld@ world, + NewtonCollision@ collisionShape + ) { + if(microbeEntity != NULL_OBJECT){ + + // It would be a huge mess to handle this here so we don't bother. + // call MicrobeOperations::removeOrganelle + assert(false, "onAddedToMicrobe called before this PlacedOrganelle was " + + "removed from previous microbe. Previous entity: " + microbeEntity); + } + + @this.world = world; + + assert(this.world !is null, "trying to create placed organelle without world"); + + microbeEntity = microbe; + + // Our coordinates are already set when this is called + // so just cache this + this.cartesianPosition = Hex::axialToCartesian(q, r); + + assert(organelleEntity == NULL_OBJECT, "PlacedOrganelle already had an entity"); + + organelleEntity = world.CreateEntity(); + + // Automatically destroyed if the parent is destroyed + world.SetEntitysParent(organelleEntity, microbeEntity); + + // Change the colour of this species to be tinted by the membrane. + auto species = MicrobeOperations::getSpeciesComponent(world, microbeEntity); + + flashColour = species.colour; + + _needsColourUpdate = true; + + Float3 offset = organelle.calculateCenterOffset(); + + auto renderNode = world.Create_RenderNode(organelleEntity); + renderNode.Scale = Float3(HEX_SIZE, HEX_SIZE, HEX_SIZE); + renderNode.Marked = true; + // The position system sets the position of this TODO: for + // performance reasons we could it set here directly as it + // never changes + renderNode.Node.setPosition(offset + this.cartesianPosition); + //maybe instead of changing this here we should do so in the generation routine. + renderNode.Node.setOrientation(Ogre::Quaternion(Ogre::Degree(rotation), + Ogre::Vector3(0, 1, 1))); + + // Add hex collision shapes + auto hexes = organelle.getHexes(); + + for(uint i = 0; i < hexes.length(); ++i){ + + Hex@ hex = hexes[i]; + + // Also add our offset to the hex offset + Float3 translation = Hex::axialToCartesian(hex.q, hex.r) + this.cartesianPosition; + + // Create the matrix with the offset + Ogre::Matrix4 hexFinalOffset(translation); + + NewtonCollision@ hexCollision = world.GetPhysicalWorld().CreateSphere( + HEX_SIZE * 2, hexFinalOffset); + + _addedCollisions.insertLast(@hexCollision); + + collisionShape.CompoundCollisionAddSubCollision(hexCollision); + } + + + auto parentRenderNode = world.GetComponent_RenderNode( + microbeEntity); + renderNode.Node.removeFromParent(); + parentRenderNode.Node.addChild(renderNode.Node); + + //Adding a mesh for the organelle. + if(organelle.mesh != ""){ + auto model = world.Create_Model(organelleEntity, renderNode.Node, organelle.mesh); + + // TODO: clean up this check + if(organelle.mesh != "flagellum.mesh"){ + model.GraphicalObject.setCustomParameter(1, + // Start non-tinted + Ogre::Vector4(1, 1, 1, 1) + ); + } + } + + // Add each OrganelleComponent + for(uint i = 0; i < components.length(); ++i){ + + // This cannot affect the collision here. It needs to do + // Organelle::addHex during construction + components[i].onAddedToMicrobe(microbeEntity, q, r, rotation, this); + } + } + + //! Alternative to onRemovedFromMicrobe called when the microbe + //! and this is being destroyed at the same time. For example when + //! closing the game + void onDestroyedWithMicrobe(ObjectID microbe){ + + // TODO: do these need handling? + // //iterating on each OrganelleComponent + // for(uint i = 0; i < components.length(); ++i){ + + // components[i].onDestroyedWithMicrobe(microbeEntity, this); + // } + + world.QueueDestroyEntity(organelleEntity); + organelleEntity = NULL_OBJECT; + microbeEntity = NULL_OBJECT; + @world = null; + } + + // Called by a microbe when this organelle has been removed from it + // + // @param microbe + // The organelle's previous owner + void onRemovedFromMicrobe(ObjectID microbe, NewtonCollision@ collisionShape){ + + LOG_INFO("PlacedOrganelle (" + organelle.name + ") removed from: " + microbeEntity); + + //iterating on each OrganelleComponent + for(uint i = 0; i < components.length(); ++i){ + + components[i].onRemovedFromMicrobe(microbeEntity, this /*, q, r*/); + } + + // We can do a quick remove from the destructor + collisionShape.CompoundCollisionBeginAddRemove(); + + // Remove our sub collisions // + for(uint i = 0; i < _addedCollisions.length(); ++i){ + + collisionShape.CompoundCollisionRemoveSubCollision(_addedCollisions[i]); + } + + collisionShape.CompoundCollisionEndAddRemove(); + _addedCollisions.resize(0); + + world.QueueDestroyEntity(organelleEntity); + organelleEntity = NULL_OBJECT; + microbeEntity = NULL_OBJECT; + @world = null; + } + + //! \todo flashOrganelle called on PlacedOrganelle but it doesn't work + void flashOrganelle(float duration, Float4 colour){ + if(flashDuration > 0) + return; + + // LOG_WARNING("flashOrganelle called on PlacedOrganelle but it doesn't work"); + flashColour = colour; + flashDuration = duration; + } + + // Sets the color of the organelle (used in editor for valid/nonvalid placement) + // Doesn't work + void setColour(Float4 colour){ + LOG_WARNING("setColour called on PlacedOrganelle but it doesn't work"); + //sceneNode.entity.setColour(colour) + } + + // ------------------------------------ // + + const Organelle@ organelle { + get const{ + return _organelle; + } + } + + private Organelle@ _organelle; + + // q and r are radial coordinates instead of cartesian + // Could use the class AxialCoordinates here + int q; + int r; + int rotation; + + // Filled from the above parameters when added to a microbe + Float3 cartesianPosition = Float3(0, 0, 0); + + // Whether or not this organelle has already divided. + bool wasSplit = false; + + // If this organelle is a duplicate of another organelle caused by splitting. + bool isDuplicate = false; + + // The "Health Bar" of the organelle constrained to [0, 2], + // ORGANELLE_HEALTH tells what different ranges mean + float compoundBin = ORGANELLE_HEALTH::ALIVE; + + // The compounds left to divide this organelle. + // Decreases every time a required compound is absorbed. + dictionary compoundsLeft; + + // The compounds that make up this organelle. They get reduced each time + // the organelle gets damaged. + dictionary composition; + + array components; + + ObjectID microbeEntity = NULL_OBJECT; + ObjectID organelleEntity = NULL_OBJECT; + + // This is the world in which the entities for this organelle exists + CellStageWorld@ world; + + // TODO: fix this + float flashDuration = 0; + + //! When flashing this is red othertimes this is the species colour + Float4 flashColour = Float4(1, 1, 1, 1); + + // TODO: make this work. This is used to show the species and the + // health of this organelle. And damange indication through + // flashColour + Float4 colourTint = Float4(1, 1, 1, 1); + + PlacedOrganelle@ sisterOrganelle = null; + + // Used for removing the added sub collisions when we are removed from a microbe + private array _addedCollisions; + + bool _needsColourUpdate = false; +} + + +// These aren't used in favor of similar approach to before where one class is customized +// with different parameters +// class Nucleus : Organelle{ + +// Nucleus(){ + +// super("nucleus"); +// } +// } + +// class Mitochondrion : Organelle{ + +// Mitochondrion(){ + +// super("mitochondrion"); +// } +// } + +// class Vacuole : Organelle{ + +// Vacuole(){ + +// super("vacuole"); +// } +// } + +// class Flagellum : Organelle{ + +// Flagellum(){ + +// super("flagellum"); +// } +// } + + + + +// // Loading stored organelles +// function Organelle.loadOrganelle(storage){ +// local name = storage:get("name", ""); +// local mass = storage:get("mass", 0.1); +// local organelle = Organelle(mass, name); +// organelle::load(storage); +// return organelle; +// } + +// function Organelle.load(storage){ +// local hexes = storage.get("hexes", {}); +// for(i = 1; i < hexes..size()){ +// local hexStorage = hexes.get(i); +// local q = hexStorage.get("q", 0); +// local r = hexStorage.get("r", 0); +// this.addHex(q, r); +// } +// this.position.q = storage.get("q", 0); +// this.position.r = storage.get("r", 0); +// this.rotation = storage.get("rotation", 0); + +// local organelleInfo = organelleTable[this.name]; +// //adding all of the components. +// for(componentName, _ in pairs(organelleInfo.components)){ +// local componentType = _G[componentName]; +// local componentData = storage.get(componentName, componentType()); +// local newComponent = componentType(nil, nil); +// newComponent.load(componentData); +// this.components[componentName] = newComponent; +// } +// } + + +// function Organelle.storage(){ +// local storage = StorageContainer.new(); +// local hexes = StorageList.new(); +// for(_, hex in pairs(this._hexes)){ +// hexStorage = StorageContainer.new(); +// hexStorage.set("q", hex.q); +// hexStorage.set("r", hex.r); +// hexes.append(hexStorage); +// } +// storage.set("hexes", hexes); +// storage.set("name", this.name); +// storage.set("q", this.position.q); +// storage.set("r", this.position.r); +// storage.set("rotation", this.rotation); +// storage.set("mass", this.mass); +// //Serializing these causes some minor issues and ){esn't serve a purpose anyway +// //storage.set("externalEdgeColour", this._externalEdgeColour) + +// //iterating on each OrganelleComponent +// for(componentName, component in pairs(this.components) ){ +// local s = component.storage(); +// assert(isNotEmpty, componentName); +// assert(s); +// storage.set(componentName, s); +// } + +// return storage; +// } + + +class EditorPlacedOrganelle{ + + //! The actual placed organelle for type checking and moving it around + PlacedOrganelle@ organelle; + + string name = "remove"; + + int rotation = 0; + + // Cached Hexes for performance + array@ hexes; +} + +// TODO: could we just use normal organelles that are inactive and add +// a render background method to it + +//! Class for handling drawing hexes in the editor for organelles +class OrganelleHexDrawer{ + + // Draws the hexes and uploads the models in the editor + void renderOrganelles(CellStageWorld@ world, EditorPlacedOrganelle@ data){ + if(data.name == "remove") + return; + + // Wouldn't it be easier to just use normal PlacedOrganelle and just move it around + assert(false, "TODO: use actual PlacedOrganelles to position things"); + + // //Getting the list hexes occupied by this organelle. + // if(data.hexes is null){ + + // // The list needs to be rotated // + // int times = data.rotation / 60; + + // //getting the hex table of the organelle rotated by the angle + // @data.hexes = rotateHexListNTimes(organelle.getHexes(), times); + // } + + // occupiedHexList = OrganelleFactory.checkSize(data); + + // //Used to get the average x and y values. + // float xSum = 0; + // float ySum = 0; + + // //Rendering a cytoplasm in each of those hexes. + // //Note: each scenenode after the first one is considered a cytoplasm by the + // // engine automatically. + // // TODO: verify the above claims + + // Float2 organelleXY = Hex::axialToCartesian(data.q, data.r); + + // uint i = 2; + // for(uint listIndex = 0; listIndex < data.hexes.length(); ++listIndex){ + + // const Hex@ hex = data.hexes[listIndex]; + + + // Float2 hexXY = Hex::axialToCartesian(hex.q, hex.r); + + // float x = organelleXY.X + hexX; + // float y = organelleYY.Y + hexY; + // xSum = xSum + x; + // ySum = ySum + y; + // i = i + 1; + // } + + // //Getting the average x and y values to render the organelle mesh in the middle. + // local xAverage = xSum / (i - 2); // Number of occupied hexes = (i - 2). + // local yAverage = ySum / (i - 2); + + // //Rendering the organelle mesh (if it has one). + // auto mesh = data.organelle.organelle.mesh; + // if(mesh ~= nil) { + + // // Create missing components to place the mesh in etc. + // if(world.GetComponent_ + + // data.sceneNode[1].meshName = mesh; + // data.sceneNode[1].transform.position = Vector3(-xAverage, -yAverage, 0); + // data.sceneNode[1].transform.orientation = Quaternion.new( + // Radian.new(Degree(data.rotation)), Vector3(0, 0, 1)); + // } + } +} + + diff --git a/scripts/microbe_stage/organelle.lua b/scripts/microbe_stage/organelle.lua deleted file mode 100644 index e1d393e8a84..00000000000 --- a/scripts/microbe_stage/organelle.lua +++ /dev/null @@ -1,550 +0,0 @@ --- How fast organelles grow. -GROWTH_SPEED_MULTILPIER = 0.5 / 1000 - --- Percentage of the compounds that compose the organelle released --- upon death (between 0.0 and 1.0). -COMPOUND_RELEASE_PERCENTAGE = 0.3 - --- Container for organelle components for all the organelle components -Organelle = class( - -- Constructor - function(self, mass, name) - - self.collisionShape = CompoundShape.new() - self.mass = mass - self.components = {} - self._hexes = {} - self.position = { - q = 0, - r = 0 - } - self.rotation = nil - - --Naming the organelle. - if name == nil then - self.name = "" - else - self.name = name - end - - -- The deviation of the organelle color from the species color - self._needsColourUpdate = true - - -- Whether or not this organelle has already divided. - self.split = false - -- If this organelle is a duplicate of another organelle caused by splitting. - self.isDuplicate = false - - -- The "Health Bar" of the organelle constrained to [0,2] - -- 0 means the organelle is dead, 1 means its normal, and 2 means - -- its ready to divide. - self.compoundBin = 1.0 - - -- The compounds left to divide this organelle. - -- Decreases every time a required compound is absorbed. - self.compoundsLeft = {} - - -- The compounds that make up this organelle. They get reduced each time - -- the organelle gets damaged. - self.composition = {} - - -- The total number of compounds we need before we can split. - self.organelleCost = 0 - - for compoundName, amount in pairs(organelleTable[name].composition) do - self.compoundsLeft[compoundName] = amount - self.composition[compoundName] = amount - self.organelleCost = self.organelleCost + amount - end - - end -) - --- Factory function for organelles -function Organelle.loadOrganelle(storage) - local name = storage:get("name", "") - local mass = storage:get("mass", 0.1) - local organelle = Organelle(mass, name) - organelle:load(storage) - return organelle -end - --- Adds a hex to this organelle --- --- @param q, r --- Axial coordinates of the new hex --- --- @returns success --- True if the hex could be added, false if there already is a hex at (q,r) -function Organelle:addHex(q, r) - assert(not self.microbeEntity, "Cannot change organelle shape while it is in a microbe") - local s = encodeAxial(q, r) - if self._hexes[s] then - return false - end - local hex = { - q = q, - r = r, - collisionShape = SphereShape.new(2) - } - local x, y = axialToCartesian(q, r) - local translation = Vector3(x, y, 0) - - -- Collision shape - self.collisionShape:addChildShape( - translation, - Quaternion.new(Radian(0), Vector3(1,0,0)), - hex.collisionShape - ) - self._hexes[s] = hex - return true -end - - --- Retrieves a hex --- --- @param q, r --- Axial coordinates of the hex --- --- @returns hex --- The hex at (q, r) or nil if there's no hex at that position -function Organelle:getHex(q, r) - local s = encodeAxial(q, r) - return self._hexes[s] -end - - -function Organelle:load(storage) - local hexes = storage:get("hexes", {}) - for i = 1,hexes:size() do - local hexStorage = hexes:get(i) - local q = hexStorage:get("q", 0) - local r = hexStorage:get("r", 0) - self:addHex(q, r) - end - self.position.q = storage:get("q", 0) - self.position.r = storage:get("r", 0) - self.rotation = storage:get("rotation", 0) - - local organelleInfo = organelleTable[self.name] - --adding all of the components. - for componentName, _ in pairs(organelleInfo.components) do - local componentType = _G[componentName] - local componentData = storage:get(componentName, componentType()) - local newComponent = componentType(nil, nil) - newComponent:load(componentData) - self.components[componentName] = newComponent - end -end - - --- Called by a microbe when this organelle has been added to it --- --- @param microbe --- The organelle's new owner --- --- @param q, r --- Axial coordinates of the organelle's center -function Organelle:onAddedToMicrobe(microbeEntity, q, r, rotation) - self.microbeEntity = microbeEntity - self.position.q = q - self.position.r = r - local x, y = axialToCartesian(q, r) - self.position.cartesian = Vector3(x,y,0) - self.rotation = rotation - - self.organelleEntity = Entity.new(g_luaEngine.currentGameState.wrapper) - self.organelleEntity:setVolatile(true) - microbeEntity:addChild(self.organelleEntity) - - -- Change the colour of this species to be tinted by the membrane. - if MicrobeSystem.getSpeciesComponent(microbeEntity) ~= nil then - local colorAsVec = MicrobeSystem.getSpeciesComponent(microbeEntity).colour - self.colour = ColourValue(colorAsVec.x, colorAsVec.y, colorAsVec.z, 1.0) - else - self.colour = ColourValue(1, 0, 1, 1) - end - self._needsColourUpdate = true - - local offset = Vector3(0,0,0) - local count = 0 - for _, hex in pairs(MicrobeSystem.getOrganelleAt(self.microbeEntity, q, r)._hexes) do - count = count + 1 - - local x, y = axialToCartesian(hex.q, hex.r) - offset = offset + Vector3(x, y, 0) - end - offset = offset / count - - self.sceneNode = OgreSceneNodeComponent.new() - self.sceneNode.transform.orientation = Quaternion.new(Radian.new(Degree(self.rotation)), - Vector3(0, 0, 1)) - self.sceneNode.transform.position = offset + self.position.cartesian - self.sceneNode.transform.scale = Vector3(HEX_SIZE, HEX_SIZE, HEX_SIZE) - self.sceneNode.transform:touch() - self.sceneNode.parent = microbeEntity - self.organelleEntity:addComponent(self.sceneNode) - - --Adding a mesh to the organelle. - local mesh = organelleTable[self.name].mesh - if mesh ~= nil then - self.sceneNode.meshName = mesh - end - - -- Add each OrganelleComponent - for _, component in pairs(self.components) do - component:onAddedToMicrobe(microbeEntity, q, r, rotation, self) - end -end - --- Called by a microbe when this organelle has been removed from it --- --- @param microbe --- The organelle's previous owner -function Organelle:onRemovedFromMicrobe() - --iterating on each OrganelleComponent - for _, component in pairs(self.components) do - component:onRemovedFromMicrobe(self.microbeEntity) - end - - self.organelleEntity:destroy() -end - - --- Removes a hex from this organelle --- --- @param q,r --- Axial coordinates of the hex to remove --- --- @returns success --- True if the hex could be removed, false if there's no hex at (q,r) -function Organelle:removeHex(q, r) - assert(not self.microbeEntity, "Cannot change organelle shape while it is in a microbe") - local s = encodeAxial(q, r) - local hex = table.remove(self._hexes, s) - if hex then - self.collisionShape:removeChildShape(hex.collisionShape) - return true - else - return false - end -end - -function Organelle:flashOrganelle(duration, colour) - if self.flashDuration == nil then - - self.flashColour = colour - self.flashDuration = duration - end -end - -function Organelle:storage() - local storage = StorageContainer.new() - local hexes = StorageList.new() - for _, hex in pairs(self._hexes) do - hexStorage = StorageContainer.new() - hexStorage:set("q", hex.q) - hexStorage:set("r", hex.r) - hexes:append(hexStorage) - end - storage:set("hexes", hexes) - storage:set("name", self.name) - storage:set("q", self.position.q) - storage:set("r", self.position.r) - storage:set("rotation", self.rotation) - storage:set("mass", self.mass) - --Serializing these causes some minor issues and doesn't serve a purpose anyway - --storage:set("externalEdgeColour", self._externalEdgeColour) - - --iterating on each OrganelleComponent - for componentName, component in pairs(self.components) do - local s = component:storage() - assert(isNotEmpty, componentName) - assert(s) - storage:set(componentName, s) - end - - return storage -end - - --- Called by Microbe:update --- --- Override this to make your organelle class do something at regular intervals --- --- @param logicTime --- The time since the last call to update() -function Organelle:update(logicTime) - if self.flashDuration ~= nil then - self.flashDuration = self.flashDuration - logicTime - local speciesColour = ColourValue(MicrobeSystem.getSpeciesComponent(self.microbeEntity).colour.x, - MicrobeSystem.getSpeciesComponent(self.microbeEntity).colour.y, - MicrobeSystem.getSpeciesComponent(self.microbeEntity).colour.z, 1) - - -- How frequent it flashes, would be nice to update the flash function to have this variable - if math.fmod(self.flashDuration,600) < 300 then - self.colour = self.flashColour - else - self.colour = speciesColour - end - - if self.flashDuration <= 0 then - self.flashDuration = nil - self.colour = speciesColour - end - - self._needsColourUpdate = true - end - - -- If the organelle is supposed to be another color. - if self._needsColourUpdate == true then - self:updateColour() - end - - -- Update each OrganelleComponent - for _, component in pairs(self.components) do - component:update(self.microbeEntity, self, logicTime) - end -end - -function Organelle:updateColour() - if self.sceneNode.entity ~= nil then - local entity = self.sceneNode.entity - --entity:tintColour(self.name, self.colour) --crashes game - - self._needsColourUpdate = false - end -end - -function Organelle:getCompoundBin() - return self.compoundBin -end - --- Gives organelles more compounds -function Organelle:growOrganelle(compoundBagComponent, logicTime) - -- Finds the total number of needed compounds. - local sum = 0.0 - - -- Finds which compounds the cell currently has. - for compoundName, amount in pairs(self.compoundsLeft) do - if compoundBagComponent:getCompoundAmount(CompoundRegistry.getCompoundId(compoundName)) >= 1 then - sum = sum + amount - end - end - - -- If sum is 0, we either have no compounds, in which case we cannot grow the organelle, or the - -- organelle is ready to split (i.e. compoundBin = 2), in which case we wait for the microbe to - -- handle the split. - if sum <= 0.0 then return end - - -- Randomly choose which of the compounds are used in reproduction. - -- Uses a roulette selection. - local id = math.random() * sum - - for compoundName, amount in pairs(self.compoundsLeft) do - if id - amount < 0 then - -- The random number is from this compound, so attempt to take it. - local amountToTake = math.min(logicTime * GROWTH_SPEED_MULTILPIER, amount) - amountToTake = compoundBagComponent:takeCompound(CompoundRegistry.getCompoundId(compoundName), amountToTake) - self.compoundsLeft[compoundName] = self.compoundsLeft[compoundName] - amountToTake - break - - else - id = id - amount - end - end - - -- Calculate the new growth value. - self:recalculateBin() -end - -function Organelle:damageOrganelle(damageAmount) - -- Flash the organelle that was damaged. - self:flashOrganelle(3000, ColourValue(1,0.2,0.2,1)) - - -- Calculate the total number of compounds we need - -- to divide now, so that we can keep this ratio. - local totalLeft = 0.0 - for _, amount in pairs(self.compoundsLeft) do - totalLeft = totalLeft + amount - end - - -- Calculate how much compounds the organelle needs to have - -- to result in a health equal to compoundBin - amount. - local damageFactor = (2.0 - self.compoundBin + damageAmount) * self.organelleCost / totalLeft - for compoundName, amount in pairs(self.compoundsLeft) do - self.compoundsLeft[compoundName] = amount * damageFactor - end - - self:recalculateBin() -end - -function Organelle:recalculateBin() - -- Calculate the new growth growth - local totalCompoundsLeft = 0.0 - for _, amount in pairs(self.compoundsLeft) do - totalCompoundsLeft = totalCompoundsLeft + amount - end - self.compoundBin = 2.0 - totalCompoundsLeft / self.organelleCost - - -- If the organelle is damaged... - if self.compoundBin < 1.0 then - if self.compoundBin <= 0.0 then - -- If it was split from a primary organelle, destroy it. - if self.isDuplicate == true then - MicrobeSystem.removeOrganelle(self.microbeEntity, self.position.q, self.position.r) - - -- Notify the organelle the sister organelle it is no longer split. - self.sisterOrganelle.wasSplit = false - return - - -- If it is a primary organelle, make sure that it's compound bin is not less than 0. - else - self.compoundBin = 0.0 - for compoundName, amount in pairs(self.composition) do - self.compoundsLeft[compoundName] = 2 * amount - end - end - end - - -- Scale the model at a slower rate (so that 0.0 is half size). - if organelleTable[self.name].components["NucleusOrganelle"] == nil then - self.sceneNode.transform.scale = Vector3((1.0 + self.compoundBin)/2, (1.0 + self.compoundBin)/2, (1.0 + self.compoundBin)/2)*HEX_SIZE - self.sceneNode.transform:touch() - end - - -- Darken the color. Will be updated on next call of update() - self.colourTint = Vector3((1.0 + self.compoundBin)/2, self.compoundBin, self.compoundBin) - self._needsColourUpdate = true - else - -- Scale the organelle model to reflect the new size. - if organelleTable[self.name].components["NucleusOrganelle"] == nil then - self.sceneNode.transform.scale = Vector3(self.compoundBin, self.compoundBin, self.compoundBin)*HEX_SIZE - self.sceneNode.transform:touch() - end - end -end - -function Organelle:reset() - -- Return the compound bin to its original state - self.compoundBin = 1.0 - for compoundName, amount in pairs(self.composition) do - self.compoundsLeft[compoundName] = amount - end - - -- Scale the organelle model to reflect the new size. - self.sceneNode.transform.scale = Vector3(1, 1, 1) * HEX_SIZE - self.sceneNode.transform:touch() - - -- If it was split from a primary organelle, destroy it. - if self.isDuplicate == true then - MicrobeSystem.removeOrganelle(self.microbeEntity, self.position.q, self.position.r) - else - self.wasSplit = false - end -end - - -function Organelle:removePhysics() - self.collisionShape:clear() -end - --- The basic organelle maker -OrganelleFactory = class( - function(self) - - end -) - --- Sets the color of the organelle (used in editor for valid/nonvalid placement) -function OrganelleFactory.setColour(sceneNode, colour) - sceneNode.entity:setColour(colour) -end - -function OrganelleFactory.makeOrganelle(data) - if not (data.name == "" or data.name == nil) then - --retrieveing the organelle info from the table - local organelleInfo = organelleTable[data.name] - - --creating an empty organelle - local organelle = Organelle(organelleInfo.mass, data.name) - - --adding all of the components. - for componentName, arguments in pairs(organelleInfo.components) do - local componentType = _G[componentName] - organelle.components[componentName] = componentType.new(arguments, data) - end - - --getting the hex table of the organelle rotated by the angle - local hexes = OrganelleFactory.checkSize(data) - - --adding the hexes to the organelle - for _, hex in pairs(hexes) do - organelle:addHex(hex.q, hex.r) - end - - return organelle - end -end - --- Draws the hexes and uploads the models in the editor -function OrganelleFactory.renderOrganelles(data) - if data.name == "remove" then - return {} - else - --Getting the list hexes occupied by this organelle. - occupiedHexList = OrganelleFactory.checkSize(data) - - --Used to get the average x and y values. - local xSum = 0 - local ySum = 0 - - --Rendering a cytoplasm in each of those hexes. - --Note: each scenenode after the first one is considered a cytoplasm by the engine automatically. - local i = 2 - for _, hex in pairs(occupiedHexList) do - local organelleX, organelleY = axialToCartesian(data.q, data.r) - local hexX, hexY = axialToCartesian(hex.q, hex.r) - local x = organelleX + hexX - local y = organelleY + hexY - local translation = Vector3(-x, -y, 0) - data.sceneNode[i].transform.position = translation - data.sceneNode[i].transform.orientation = Quaternion.new( - Radian.new(Degree(data.rotation)), Vector3(0, 0, 1)) - xSum = xSum + x - ySum = ySum + y - i = i + 1 - end - - --Getting the average x and y values to render the organelle mesh in the middle. - local xAverage = xSum / (i - 2) -- Number of occupied hexes = (i - 2). - local yAverage = ySum / (i - 2) - - --Rendering the organelle mesh (if it has one). - local mesh = organelleTable[data.name].mesh - if(mesh ~= nil) then - data.sceneNode[1].meshName = mesh - data.sceneNode[1].transform.position = Vector3(-xAverage, -yAverage, 0) - data.sceneNode[1].transform.orientation = Quaternion.new( - Radian.new(Degree(data.rotation)), Vector3(0, 0, 1)) - end - end -end - --- Checks which hexes an organelle occupies -function OrganelleFactory.checkSize(data) - if data.name == "remove" then - return {} - else - --getting the angle the organelle has - --(and setting one if it doesn't have one). - if data.rotation == nil then - data.rotation = 0 - end - local angle = data.rotation / 60 - - --getting the hex table of the organelle rotated by the angle - local hexes = rotateHexListNTimes(organelleTable[data.name].hexes, angle) - return hexes - end -end diff --git a/scripts/microbe_stage/organelle_component.as b/scripts/microbe_stage/organelle_component.as new file mode 100644 index 00000000000..4386ccb12bd --- /dev/null +++ b/scripts/microbe_stage/organelle_component.as @@ -0,0 +1,103 @@ + +//! Base class for organelle components. +//! \note Unlike Organelle and PlacedOrganelle instanced of classes derived from this +//! are directly added to PlacedOrganelle so these classes may change state in +//! the update methods +abstract class OrganelleComponent{ + + // Constructor. + OrganelleComponent(){ + + } + + // Event handler for an organelle added to a microbe. + // + // @param microbe + // The microbe this organelle is added to. + // + // @param q + // q component of the organelle relative position in the microbe, + // in axial coordinates (see hex.lua). + // + // @param r + // r component of the organelle relative position in the microbe, + // in axial coordinates (see hex.lua). + // + // @param rotation + // The rotation this organelle has on the microbe. + // it can be either 0, 60, 120, 180, 240 or 280. + // + // @param organelle + // The organelle object that is made up of these components. + void + onAddedToMicrobe( + ObjectID microbeEntity, + int q, int r, int rotation, + PlacedOrganelle@ organelle + ) { + assert(false, "OrganelleComponent::onAddedToMicrobe not overridden"); + } + + // Event handler for an organelle removed from a microbe. + // + // @param microbe + // The microbe this organelle is removed from. + // These aren't passed, at least not when the microbe is dying so they are now removed + // from here as well + // @param organelle + // MUST BE THE SAME ORGANELLE this was added to + void + onRemovedFromMicrobe( + ObjectID microbeEntity, + PlacedOrganelle@ organelle + ) { + + } + + // Function executed at regular intervals + // + // @param microbe + // The microbe this organelle is attached. + // + // @param organelle + // The organelle that has this component. + // + // @param logicTime + // The time transcurred (in milliseconds) between this call + // to OrganelleComponent:update() and the previous one. + void + update( + ObjectID microbeEntity, + PlacedOrganelle@ organelle, + int logicTime + ) { + + } + + // // Function for saving organelle information. + // // If an organelle depends on an atribute, then it should be saved + // // the data gets retrieved later by OrganelleComponent:load(). + // // The return value should be a new StorageContainer object + // // filled with the data to save. + // StorageContainer@ storage(){ + // return StorageContainer(); + // } + + // // Function for loading organelle information. + // // + // // @param storage + // // The StorageContainer object that has the organelle information + // // (the one saved in OrganelleComponent:storage()). + // void OrganelleComponent:load(StorageContainer@ storage){ + + // } +} + + + + + + + + + diff --git a/scripts/microbe_stage/organelle_component.lua b/scripts/microbe_stage/organelle_component.lua deleted file mode 100644 index ea51d5cb290..00000000000 --- a/scripts/microbe_stage/organelle_component.lua +++ /dev/null @@ -1,80 +0,0 @@ ---Base class for organelle components. -OrganelleComponent = class( - -- Constructor. - -- - -- @param arguments - -- The parameters of the constructor, defined in organelle_table.lua. - -- - -- @param data - -- The organelle data taken from the make function in organelle.lua. - function(self, arguments, data) - end -) - --- Event handler for an organelle added to a microbe. --- --- @param microbe --- The microbe this organelle is added to. --- --- @param q --- q component of the organelle relative position in the microbe, --- in axial coordinates (see hex.lua). --- --- @param r --- r component of the organelle relative position in the microbe, --- in axial coordinates (see hex.lua). --- --- @param rotation --- The rotation this organelle has on the microbe. --- it can be either 0, 60, 120, 180, 240 or 280. --- --- @param self --- The organelle object that is made up of these components. -function OrganelleComponent:onAddedToMicrobe(microbeEntity, q, r, rotation, organelle) -end - --- Event handler for an organelle removed from a microbe. --- --- @param microbe --- The microbe this organelle is removed from. --- --- @param q --- q component of the organelle relative position in the microbe, --- in axial coordinates (see hex.lua). --- --- @param r --- r component of the organelle relative position in the microbe, --- in axial coordinates (see hex.lua). -function OrganelleComponent:onRemovedFromMicrobe(microbeEntity, q, r) -end - --- Function executed at regular intervals --- --- @param microbe --- The microbe this organelle is attached. --- --- @param organelle --- The organelle that has this component. --- --- @param logicTime --- The time transcurred (in milliseconds) between this call --- to OrganelleComponent:update() and the previous one. -function OrganelleComponent:update(microbeEntity, organelle, logicTime) -end - --- Function for saving organelle information. --- If an organelle depends on an atribute, then it should be saved --- the data gets retrieved later by OrganelleComponent:load(). --- The return value should be a new StorageContainer object --- filled with the data to save. -function OrganelleComponent:storage() - return StorageContainer.new() -end - --- Function for loading organelle information. --- --- @param storage --- The StorageContainer object that has the organelle information --- (the one saved in OrganelleComponent:storage()). -function OrganelleComponent:load(storage) -end diff --git a/scripts/microbe_stage/organelle_table.as b/scripts/microbe_stage/organelle_table.as new file mode 100644 index 00000000000..bbaa24ed2a0 --- /dev/null +++ b/scripts/microbe_stage/organelle_table.as @@ -0,0 +1,514 @@ +// TODO: update this +/* +Organelle atributes: + mass: How heavy an organelle is. Affects speed, mostly. + + components: A table with the components an organelle has, plus + the arguments the component needs to initialize. + Refer to the particular component's lua file for + more information. + + mpCost: The cost (in mutation points) an organelle costs in the + microbe editor. + + mesh: The name of the mesh file of the organelle. + It has to be in the models folder. + + hexes: A table of the hexes that the organelle occupies. + Each hex it's represented by a table that looks like this: + {["q"]=q, ["r"]=r} + where q and r are the hex position in axial coordinates. + + gene: The letter that will be used by the auto-evo system to + identify this organelle. + + chanceToCreate: The (relative) chance this organelle will appear in a randomly + generated or mutated microbe (to do roulette selection). + + processes: A table with all the processes this organelle does, + and the capacity of the process (the amount of + process that can be made in one second). + TODO: put it in the procesOrganelle component? + + composition: A table with the compounds that compost the organelle. + They are needed in order to split the organelle, and a + percentage of them is released upon death of the microbe. +*/ +#include "organelle.as" +#include "organelle_component.as" + +#include "process_table.as" + +// For AxialCoordinates +#include "configs.as" + +// Need to include all the used organelle types for the factory functions +#include "nucleus_organelle.as" +#include "storage_organelle.as" +#include "processor_organelle.as" +#include "agent_vacuole.as" +#include "movement_organelle.as" + +//! Factory typedef for OrganelleComponent +funcdef OrganelleComponent@ OrganelleComponentFactoryFunc(); + +class OrganelleComponentFactory{ + + OrganelleComponentFactory(OrganelleComponentFactoryFunc@ f, const string &in name){ + + @factory = f; + this.name = name; + } + + OrganelleComponentFactoryFunc@ factory; + string name; +} + +//! This replaced the old tables that specified things for cells. +//! This is clearer as to what are valid properties +class OrganelleParameters{ + + OrganelleParameters(const string &in name){ + + this.name = name; + } + float mass = 0; + string name; + string gene = "INVALID"; + string mesh; + + //! Chance of randomly generating this (used by procedural_microbes.as) + float chanceToCreate = 0.0; + + //! The factories for the components that define what this organelle does + array components; + + array processes; + + array hexes; + + //! The initial amount of compounds this organelle consists of + dictionary initialComposition; + + //! Cost in mutation points + int mpCost = 0; +} + +//! Cache the result if called multiple times for the same world +Organelle@ getOrganelleDefinition(const string &in name){ + + Organelle@ organelle = cast(_mainOrganelleTable[name]); + + if(organelle is null){ + + LOG_ERROR("getOrganelleDefinition: no organelle named '" + name + "'"); + PrintCallStack(); + } + + return organelle; +} + +// ------------------------------------ // +// Private part starts here don't directly call or read these things from any other file +// Only thing you'll need to modify is the "Main organelle table" below + +// Don't touch this from anywhere except setupOrganelles +// use getOrganelleDefinition for accessing +dictionary _mainOrganelleTable; + +// Factory functions for all the organelle components + +OrganelleComponent@ makeNucleusOrganelle(){ + return NucleusOrganelle(); +} + +OrganelleComponentFactory@ nucleusComponentFactory = OrganelleComponentFactory( + @makeNucleusOrganelle, "NucleusOrganelle" +); + +class StorageOrganelleFactory{ + + StorageOrganelleFactory(float capacity){ + + this.capacity = capacity; + } + + OrganelleComponent@ makeStorageOrganelle(){ + return StorageOrganelle(capacity); + } + + float capacity; +} + +OrganelleComponentFactory@ storageOrganelleFactory(float capacity){ + + auto factory = StorageOrganelleFactory(capacity); + return OrganelleComponentFactory( + OrganelleComponentFactoryFunc(factory.makeStorageOrganelle), "StorageOrganelle"); +} + +class ProcessorOrganelleFactory{ + + ProcessorOrganelleFactory(float colourChangeFactor){ + + this.colourChangeFactor = colourChangeFactor; + } + + OrganelleComponent@ makeProcessorOrganelle(){ + return ProcessorOrganelle(colourChangeFactor); + } + + float colourChangeFactor; +} + +OrganelleComponentFactory@ processorOrganelleFactory(float colourChangeFactor){ + + auto factory = ProcessorOrganelleFactory(colourChangeFactor); + return OrganelleComponentFactory( + OrganelleComponentFactoryFunc(factory.makeProcessorOrganelle), "ProcessorOrganelle"); +} + + +class AgentVacuoleFactory{ + + AgentVacuoleFactory(const string &in compound, const string &in process){ + + this.compound = compound; + this.process = process; + } + + OrganelleComponent@ makeAgentVacuole(){ + return AgentVacuole(compound, process); + } + + string compound; + string process; +} + +OrganelleComponentFactory@ agentVacuoleFactory(const string &in compound, + const string &in process +) { + auto factory = AgentVacuoleFactory(compound, process); + return OrganelleComponentFactory( + OrganelleComponentFactoryFunc(factory.makeAgentVacuole), + "AgentVacuole"); +} + + +class MovementOrganelleFactory{ + + MovementOrganelleFactory(float momentum, float torque){ + + this.momentum = momentum; + this.torque = torque; + } + + OrganelleComponent@ makeMovementOrganelle(){ + return MovementOrganelle(momentum, torque); + } + + float momentum; + float torque; +} + +OrganelleComponentFactory@ movementOrganelleFactory(float momentum, float torque){ + + auto factory = MovementOrganelleFactory(momentum, torque); + return OrganelleComponentFactory( + OrganelleComponentFactoryFunc(factory.makeMovementOrganelle), + "MovementOrganelle"); +} + + +// ------------------------------------ // +// Sets up the organelle table +void setupOrganelles(){ + + assert(SimulationParameters::compoundRegistry().getSize() > 0, + "Compound registry is empty"); + + _mainOrganelleTable = dictionary(); + + // + // + // ------------------------------------ // + // Main organelle table is now here + // + + // ------------------------------------ // + // Nucleus + auto nucleusParameters = OrganelleParameters("nucleus"); + + nucleusParameters.mass = 0.7; + nucleusParameters.gene = "N"; + nucleusParameters.mesh = "nucleus.mesh"; + nucleusParameters.chanceToCreate = 0; // Not randomly generated. + nucleusParameters.mpCost = 0; //it's not supossed to be purchased. + nucleusParameters.initialComposition = { + {"aminoacids", 4} + }; + nucleusParameters.components = { + nucleusComponentFactory + }; + nucleusParameters.processes = { + TweakedProcess("fattyAcidSynthesis", 0.2), + TweakedProcess("aminoAcidSynthesis", 0.2) + }; + nucleusParameters.hexes = { + Int2(0, 0), + Int2(1, 0), + Int2(0, 1), + Int2(0, -1), + Int2(1, -1), + Int2(-1, 1), + Int2(-1, 0), + Int2(1, 1), + Int2(0, 2), + Int2(-1, 2) + }; + + _addOrganelleToTable(Organelle(nucleusParameters)); + + + // ------------------------------------ // + // Cytoplasm + auto cytoplasmParameters = OrganelleParameters("cytoplasm"); + + cytoplasmParameters.mass = 0.1; + cytoplasmParameters.gene = "Y"; + cytoplasmParameters.mesh = ""; //it's an empty hex + cytoplasmParameters.chanceToCreate = 1; + cytoplasmParameters.mpCost = 5; + cytoplasmParameters.initialComposition = { + {"aminoacids", 3}, + {"glucose", 2} + // fattyacids = 0 :/ + }; + cytoplasmParameters.components = { + storageOrganelleFactory(10.0f) + }; + cytoplasmParameters.hexes = { + Int2(0, 0), + }; + + _addOrganelleToTable(Organelle(cytoplasmParameters)); + + // ------------------------------------ // + // Chloroplast + auto chloroplastParameters = OrganelleParameters("chloroplast"); + + chloroplastParameters.mass = 0.4; + chloroplastParameters.gene = "H"; + chloroplastParameters.mesh = "chloroplast.mesh"; + chloroplastParameters.chanceToCreate = 2; + chloroplastParameters.mpCost = 20; + chloroplastParameters.initialComposition = { + {"aminoacids", 4}, + {"glucose", 2} + // fattyacids = 0 :/ + }; + chloroplastParameters.components = { + processorOrganelleFactory(1.0) + }; + chloroplastParameters.processes = { + TweakedProcess("photosynthesis", 0.2) + }; + chloroplastParameters.hexes = { + Int2(0, 0), + Int2(0, -1), + Int2(1, -1) + }; + + _addOrganelleToTable(Organelle(chloroplastParameters)); + + // ------------------------------------ // + // Oxytoxy + auto oxytoxyParameters = OrganelleParameters("oxytoxy"); + + oxytoxyParameters.mass = 0.3; + oxytoxyParameters.gene = "T"; + oxytoxyParameters.mesh = "oxytoxy.mesh"; + oxytoxyParameters.chanceToCreate = 1; + oxytoxyParameters.mpCost = 40; + oxytoxyParameters.initialComposition = { + {"aminoacids", 4}, + {"glucose", 2} + // fattyacids = 0 :/ + }; + oxytoxyParameters.components = { + agentVacuoleFactory("oxytoxy", "oxytoxySynthesis") + }; + oxytoxyParameters.processes = { + TweakedProcess("oxytoxySynthesis", 0.05) + }; + oxytoxyParameters.hexes = { + Int2(0, 0) + }; + + _addOrganelleToTable(Organelle(oxytoxyParameters)); + + + // ------------------------------------ // + // Mitochondrion + auto mitochondrionParameters = OrganelleParameters("mitochondrion"); + + mitochondrionParameters.mass = 0.3; + mitochondrionParameters.gene = "M"; + mitochondrionParameters.mesh = "mitochondrion.mesh"; + mitochondrionParameters.chanceToCreate = 3; + mitochondrionParameters.mpCost = 20; + mitochondrionParameters.initialComposition = { + {"aminoacids", 4}, + {"glucose", 2} + // fattyacids = 0 :/ + }; + mitochondrionParameters.components = { + processorOrganelleFactory(1.0f) + }; + mitochondrionParameters.processes = { + TweakedProcess("respiration", 0.07) + }; + mitochondrionParameters.hexes = { + Int2(0, 0), + Int2(0, -1) + }; + + _addOrganelleToTable(Organelle(mitochondrionParameters)); + + // ------------------------------------ // + // Vacuole + auto vacuoleParameters = OrganelleParameters("vacuole"); + + vacuoleParameters.mass = 0.4; + vacuoleParameters.gene = "V"; + vacuoleParameters.mesh = "vacuole.mesh"; + vacuoleParameters.chanceToCreate = 3; + vacuoleParameters.mpCost = 15; + vacuoleParameters.initialComposition = { + {"aminoacids", 4}, + {"glucose", 2} + // fattyacids = 0 :/ + }; + vacuoleParameters.components = { + storageOrganelleFactory(100.0f) + }; + vacuoleParameters.hexes = { + Int2(0, 0) + }; + + _addOrganelleToTable(Organelle(vacuoleParameters)); + + // ------------------------------------ // + // Flagellum + auto flagellumParameters = OrganelleParameters("flagellum"); + + flagellumParameters.mass = 0.3; + flagellumParameters.gene = "F"; + flagellumParameters.mesh = "flagellum.mesh"; + flagellumParameters.chanceToCreate = 3; + flagellumParameters.mpCost = 25; + flagellumParameters.initialComposition = { + {"aminoacids", 4}, + {"glucose", 2} + // fattyacids = 0 :/ + }; + flagellumParameters.components = { + movementOrganelleFactory(20, 300) + }; + flagellumParameters.hexes = { + Int2(0, 0) + }; + + _addOrganelleToTable(Organelle(flagellumParameters)); + + //prokaryotic Organelles (all meshes are placeholders)// + + // ------------------------------------ // + // Respiratory Protien + auto respiratoryProtien = OrganelleParameters("respiartoryProteins"); + + respiratoryProtien.mass = 0.1; + respiratoryProtien.gene = "m"; + respiratoryProtien.mesh = "mitochondrion.mesh"; + respiratoryProtien.chanceToCreate = 0; + respiratoryProtien.mpCost = 20; + respiratoryProtien.initialComposition = { + {"aminoacids", 2}, + {"glucose", 1} + // fattyacids = 0 :/ + }; + respiratoryProtien.components = { + processorOrganelleFactory(1.0f), + storageOrganelleFactory(25.0f) + }; + respiratoryProtien.processes = { + TweakedProcess("respiration", 0.02) + }; + respiratoryProtien.hexes = { + Int2(0, 0), + }; + + _addOrganelleToTable(Organelle(respiratoryProtien)); + + // Photosynthetic Protien + auto photosyntheticProtein = OrganelleParameters("photosyntheticProteins"); + + photosyntheticProtein.mass = 0.1; + photosyntheticProtein.gene = "h"; + photosyntheticProtein.mesh = "chloroplast.mesh"; + photosyntheticProtein.chanceToCreate = 0; + photosyntheticProtein.mpCost = 20; + photosyntheticProtein.initialComposition = { + {"aminoacids", 2}, + {"glucose", 1} + // fattyacids = 0 :/ + }; + photosyntheticProtein.components = { + processorOrganelleFactory(1.0f), + storageOrganelleFactory(25.0f) + }; + photosyntheticProtein.processes = { + TweakedProcess("photosynthesis", 0.05) + }; + photosyntheticProtein.hexes = { + Int2(0, 0), + }; + + _addOrganelleToTable(Organelle(photosyntheticProtein)); + + // Photosynthetic Protien + auto oxytoxyProtein = OrganelleParameters("oxytoxyProteins"); + + oxytoxyProtein.mass = 0.1; + oxytoxyProtein.gene = "t"; + oxytoxyProtein.mesh = "oxytoxy.mesh"; + oxytoxyProtein.chanceToCreate = 0; + oxytoxyProtein.mpCost = 20; + oxytoxyProtein.initialComposition = { + {"aminoacids", 2}, + {"glucose", 1} + // fattyacids = 0 :/ + }; + oxytoxyProtein.components = { + agentVacuoleFactory("oxytoxy", "oxytoxySynthesis"), + storageOrganelleFactory(25.0f) + }; + oxytoxyProtein.processes = { + TweakedProcess("oxytoxySynthesis", 0.05) + }; + oxytoxyProtein.hexes = { + Int2(0, 0), + }; + + _addOrganelleToTable(Organelle(oxytoxyProtein)); + + // ------------------------------------ // + // Setup the organelle letters + setupOrganelleLetters(); +} + +void _addOrganelleToTable(Organelle@ organelle){ + + _mainOrganelleTable[organelle.name] = @organelle; +} + diff --git a/scripts/microbe_stage/organelle_table.lua b/scripts/microbe_stage/organelle_table.lua deleted file mode 100644 index 7b489c2f5f4..00000000000 --- a/scripts/microbe_stage/organelle_table.lua +++ /dev/null @@ -1,228 +0,0 @@ ---[[ -Organelle atributes: - mass: How heavy an organelle is. Affects speed, mostly. - - components: A table with the components an organelle has, plus - the arguments the component needs to initialize. - Refer to the particular component's lua file for - more information. - - mpCost: The cost (in mutation points) an organelle costs in the - microbe editor. - - mesh: The name of the mesh file of the organelle. - It has to be in the models folder. - - hexes: A table of the hexes that the organelle occupies. - Each hex it's represented by a table that looks like this: - {["q"]=q, ["r"]=r} - where q and r are the hex position in axial coordinates. - - gene: The letter that will be used by the auto-evo system to - identify this organelle. - - chanceToCreate: The (relative) chance this organelle will appear in a randomly - generated or mutated microbe (to do roulette selection). - - processes: A table with all the processes this organelle does, - and the capacity of the process (the amount of - process that can be made in one second). - TODO: put it in the procesOrganelle component? - - composition: A table with the compounds that compost the organelle. - They are needed in order to split the organelle, and a - percentage of them is released upon death of the microbe. -]] - -organelleTable = { - ["nucleus"] = { - mass = 0.7, - gene = "N", - chanceToCreate = 0, -- Not randomly generated. - - components = { - ["NucleusOrganelle"] = {} - }, - - processes = { - ["FattyAcidSynthesis"] = 0.2, - ["AminoAcidSynthesis"] = 0.2 - }, - - mpCost = 0, --it's not supossed to be purchased. - mesh = "nucleus.mesh", - hexes = { - {["q"]=0, ["r"]=0}, - {["q"]=1, ["r"]=0}, - {["q"]=0, ["r"]=1}, - {["q"]=0, ["r"]=-1}, - {["q"]=1, ["r"]=-1}, - {["q"]=-1, ["r"]=1}, - {["q"]=-1, ["r"]=0}, - {["q"]=-1, ["r"]=-1}, - {["q"]=0, ["r"]=-2}, - {["q"]=1, ["r"]=-2} - }, - - composition = { - aminoacids = 4 - } - }, - - ["cytoplasm"] = { - components = { - ["StorageOrganelle"] = { - capacity = 10.0 - } - }, - - mass = 0.1, - gene = "Y", - chanceToCreate = 1, - mpCost = 5, - mesh = nil, --it's an empty hex - hexes = { - {["q"]=0, ["r"]=0} - }, - - composition = { - aminoacids = 3, - glucose = 2, - -- fattyacids = 0 :/ - } - }, - - ["chloroplast"] = { - components = { - ["ProcessOrganelle"] = { - colourChangeFactor = 1.0, - - - } - }, - - processes = { - ["Photosynthesis"] = 0.2 - }, - - mass = 0.4, - gene = "H", - chanceToCreate = 2, - mpCost = 20, - mesh = "chloroplast.mesh", - hexes = { - {["q"]=0, ["r"]=0}, - {["q"]=1, ["r"]=0}, - {["q"]=0, ["r"]=1} - }, - - composition = { - aminoacids = 4, - glucose = 2, - -- fattyacids = 0 :/ - } - }, - - ["oxytoxy"] = { - components = { - ["AgentVacuole"] = { - compound = "oxytoxy", - process = "OxyToxySynthesis" - } - }, - - processes = { - ["OxyToxySynthesis"] = 0.05 - }, - - mass = 0.3, - gene = "T", - chanceToCreate = 1, - mpCost = 40, - mesh = "oxytoxy.mesh", - hexes = { - {["q"]=0, ["r"]=0} - }, - - composition = { - aminoacids = 4, - glucose = 2, - -- fattyacids = 0 :/ - } - }, - - ["mitochondrion"] = { - components = { - ["ProcessOrganelle"] = { - colourChangeFactor = 1.0, - } - }, - - processes = { - ["Respiration"] = 0.07 - }, - - mass = 0.3, - gene = "M", - chanceToCreate = 3, - mpCost = 20, - mesh = "mitochondrion.mesh", - hexes = { - {["q"]=0, ["r"]=0}, - {["q"]=0, ["r"]=1} - }, - - composition = { - aminoacids = 4, - glucose = 2, - -- fattyacids = 0 :/ - } - }, - - ["vacuole"] = { - components = { - ["StorageOrganelle"] = { - capacity = 100.0 - } - }, - - mass = 0.4, - gene = "V", - chanceToCreate = 3, - mpCost = 15, - mesh = "vacuole.mesh", - hexes = { - {["q"]=0, ["r"]=0}, - }, - - composition = { - aminoacids = 4, - glucose = 2, - -- fattyacids = 0 :/ - } - }, - - ["flagellum"] = { - components = { - ["MovementOrganelle"] = { - momentum = 20, - torque = 300 - } - }, - - mass = 0.3, - gene = "F", - chanceToCreate = 3, - mpCost = 25, - mesh = "flagellum.mesh", - hexes = { - {["q"]=0, ["r"]=0}, - }, - - composition = { - aminoacids = 4, - glucose = 2, - -- fattyacids = 0 :/ - } - } -} \ No newline at end of file diff --git a/scripts/microbe_stage/procedural_microbes.as b/scripts/microbe_stage/procedural_microbes.as new file mode 100644 index 00000000000..6ebad2c4f6d --- /dev/null +++ b/scripts/microbe_stage/procedural_microbes.as @@ -0,0 +1,188 @@ +#include "configs.as" +#include "nucleus_organelle.as" +#include "hex.as" + +// Limits the size of the initial stringCodes +const auto MIN_INITIAL_LENGTH = 5; +const auto MAX_INITIAL_LENGTH = 15; +float MAX_CHANCE_SCORE = 0; + +dictionary organelleLetters = {}; +array VALID_ORGANELLES = {}; +array VALID_ORGANELLE_LETTERS = {}; +array VALID_ORGANELLE_CHANCES = {}; + +//! Called from setupOrganelles +void setupOrganelleLetters(){ + + auto keys = _mainOrganelleTable.getKeys(); + + for(uint i = 0; i < keys.length(); ++i){ + + auto organelleName = keys[i]; + auto organelleInfo = getOrganelleDefinition(organelleName); + + // Getting the organelle letters from the organelle table. + organelleLetters[organelleInfo.gene] = organelleName; + + if(!organelleInfo.hasComponent(nucleusComponentFactory.name)){ + + VALID_ORGANELLES.insertLast(organelleName); + VALID_ORGANELLE_CHANCES.insertLast(organelleInfo.chanceToCreate); + VALID_ORGANELLE_LETTERS.insertLast(organelleInfo.gene); + + // Getting the max chance score for the roulette selection. + MAX_CHANCE_SCORE += organelleInfo.chanceToCreate; + } + } +} + +// Returns a random organelle letter +// TODO: verify that this has a good chance of returning also the last organelle +string getRandomLetter(){ + float i = GetEngine().GetRandom().GetNumber(0.f, MAX_CHANCE_SCORE); + + for(uint index = 0; index < VALID_ORGANELLES.length(); ++index){ + + i -= VALID_ORGANELLE_CHANCES[index]; + + if(i <= 0){ + return VALID_ORGANELLE_LETTERS[index]; + } + } + + // Just in case + LOG_WARNING("getRandomLetter: just in case case hit"); + return getOrganelleDefinition("cytoplasm").gene; +} + +// Checks whether an organelle in a certain position would fit within a list of other organelles. +bool isValidPlacement(const string &in organelleName, int q, int r, int rotation, + const array &in organelleList +) { + // This is super hacky :/ + // this is now slightly less hacky + auto organelleHexes = getOrganelleDefinition(organelleName).getRotatedHexes(rotation); + + for(uint i = 0; i < organelleList.length(); ++i){ + + auto otherOrganelle = organelleList[i]; + + auto otherOrganelleHexes = getOrganelleDefinition(otherOrganelle.type).getRotatedHexes( + otherOrganelle.rotation); + + for(uint thisHexIndex = 0; thisHexIndex < organelleHexes.length(); ++thisHexIndex){ + + for(uint otherHexIndex = 0; otherHexIndex < otherOrganelleHexes.length(); + ++otherHexIndex) + { + const auto hex = organelleHexes[thisHexIndex]; + const auto otherHex = otherOrganelleHexes[otherHexIndex]; + if(hex.q + q == otherHex.q + otherOrganelle.q && + hex.r + r == otherHex.r + otherOrganelle.r) + { + return false; + } + } + } + } + + return true; +} + +// Finds a valid position to place the organelle and returns it +// Maybe the values should be saved? +OrganelleTemplatePlaced@ getPosition(const string &in organelleName, + const array &in organelleList +) { + int q = 0; + int r = 0; + + // Checks whether the center is free. + for(int j = 0; j <= 5; ++j){ + int rotation = 360 * j / 6; + if(isValidPlacement(organelleName, q, r, rotation, organelleList)){ + return OrganelleTemplatePlaced(organelleName, q, r, rotation+180); + } + } + + // Moving the center one hex to the bottom. + // This way organelles are "encouraged" to be on the bottom, rather than on the top, + // which in turn means the flagellum are more likely to be on the back side of the cell. + auto initialOffset = Int2(HEX_NEIGHBOUR_OFFSET[formatInt(int(HEX_SIDE::BOTTOM))]); + q = q + initialOffset.X; + r = r + initialOffset.Y; + + // Spiral search for space for the organelle + int radius = 1; + while(true){ + //Moves into the ring of radius "radius" and center the old organelle + Int2 radiusOffset = Int2(HEX_NEIGHBOUR_OFFSET[ + formatInt(int(HEX_SIDE::BOTTOM_LEFT))]); + q = q + radiusOffset.X; + r = r + radiusOffset.Y; + + //Iterates in the ring + for(int side = 1; side <= 6; ++side){ + Int2 offset = Int2(HEX_NEIGHBOUR_OFFSET[formatInt(side)]); + //Moves "radius" times into each direction + for(int i = 1; i <= radius; ++i){ + q = q + offset.X; + r = r + offset.Y; + + //Checks every possible rotation value. + for(int j = 0; j <= 5; ++j){ + + int rotation = (360 * j / 6); + if(isValidPlacement(organelleName, q, r, rotation, organelleList)){ + return OrganelleTemplatePlaced(organelleName, q, r, rotation+180); + } + } + } + } + ++radius; + } + + return null; +} + +// Creates a list of organelles from the stringCode. +array@ positionOrganelles(const string &in stringCode){ + // TODO: remove once this works + LOG_INFO("DEBUG: positionOrganelles stringCode: " + stringCode); + + array@ result = array(); + array organelleList; + + for(uint i = 0; i < stringCode.length(); ++i){ + + OrganelleTemplatePlaced@ pos; + const auto letter = CharacterToString(stringCode[i]); + // LOG_WRITE(formatUInt(i) + ": " + letter); + string name = string(organelleLetters[letter]); + //this places the nucleous + if(i == 0){ + + @pos = OrganelleTemplatePlaced(name, 0, 0, 180); + + } else { + + @pos = getPosition(name, organelleList); + } + + if(pos.type == ""){ + + assert(false, "positionOrganelles: organelleLetters didn't have the " + "current letter: " + letter); + } + + organelleList.insertLast(pos); + result.insertLast(PlacedOrganelle(getOrganelleDefinition(pos.type), pos.q, pos.r, + pos.rotation)); + } + + // Make sure all were added + assert(stringCode.length() == result.length()); + + return result; +} diff --git a/scripts/microbe_stage/procedural_microbes.lua b/scripts/microbe_stage/procedural_microbes.lua deleted file mode 100644 index 397fc63e314..00000000000 --- a/scripts/microbe_stage/procedural_microbes.lua +++ /dev/null @@ -1,135 +0,0 @@ --- Limits the size of the initial stringCodes -local MIN_INITIAL_LENGTH = 5 -local MAX_INITIAL_LENGTH = 15 -local MAX_CHANCE_SCORE = 0 - -organelleLetters = {} -VALID_ORGANELLES = {} - -for organelleName, organelleInfo in pairs(organelleTable) do - -- Getting the organelle letters from the organelle table. - organelleLetters[organelleInfo.gene] = organelleName - - if organelleInfo.components.NucleusOrganelle == nil then - table.insert(VALID_ORGANELLES, organelleName) - - -- Getting the max chance score for the roulette selection. - MAX_CHANCE_SCORE = MAX_CHANCE_SCORE + organelleInfo.chanceToCreate - end -end - --- Returns a random organelle letter -function getRandomLetter() - i = math.random(0, MAX_CHANCE_SCORE) - - for _, organelleName in pairs(VALID_ORGANELLES) do - i = i - organelleTable[organelleName].chanceToCreate - - if i <= 0 then - return organelleTable[organelleName].gene - end - end - - -- Just in case - return organelleTable["cytoplasm"].gene -end - --- Checks whether an organelle in a certain position would fit within a list of other organelles. -function isValidPlacement(organelleName, q, r, rotation, organelleList) - -- This is super hacky :/ - local data = { - ["name"] = organelleName, - ["q"] = q, - ["r"] = r, - ["rotation"] = rotation - } - - local organelleHexes = OrganelleFactory.checkSize(data) - - for _, otherOrganelle in pairs(organelleList) do - local otherOrganelleHexes = OrganelleFactory.checkSize(otherOrganelle) - for __, hex in pairs(organelleHexes) do - for ___, otherHex in pairs(otherOrganelleHexes) do - if hex.q + q == otherHex.q + otherOrganelle.q and hex.r + r == otherHex.r + otherOrganelle.r then - return false - end - end - end - end - - return true -end - --- Finds a valid position to place the organelle and returns it --- Maybe the values should be saved? -function getPosition(organelleName, organelleList) - - local q = 0 - local r = 0 - - -- Checks whether the center is free. - for j = 0, 5 do - rotation = 360 * j / 6 - if isValidPlacement(organelleName, q, r, rotation, organelleList) then - return q, r, rotation - end - end - - -- Moving the center one hex to the bottom. - -- This way organelles are "encouraged" to be on the bottom, rather than on the top, - -- which in turn means the flagellum are more likely to be on the back side of the cell. - q = q + HEX_NEIGHBOUR_OFFSET[HEX_SIDE.BOTTOM][1] - r = r + HEX_NEIGHBOUR_OFFSET[HEX_SIDE.BOTTOM][2] - - -- Spiral search for space for the organelle - local radius = 1 - while true do - -- Moves into the ring of radius "radius" and center (0, -1) - q = q + HEX_NEIGHBOUR_OFFSET[HEX_SIDE.BOTTOM_LEFT][1] - r = r + HEX_NEIGHBOUR_OFFSET[HEX_SIDE.BOTTOM_LEFT][2] - - --I terates in the ring - for side = 1, 6 do -- Necesary due to lua not ordering the tables. - local offset = HEX_NEIGHBOUR_OFFSET[side] - -- Moves "radius" times into each direction - for i = 1, radius do - q = q + offset[1] - r = r + offset[2] - --print(q, r) - - -- Checks every possible rotation value. - for j = 0, 5 do - rotation = 360 * j / 6 - if isValidPlacement(organelleName, q, r, rotation, organelleList) then - return q, r, rotation - end - end - end - end - radius = radius + 1 - end -end - --- Creates a list of organelles from the stringCode. -function positionOrganelles(stringCode) - local organelleList = {{ - ["name"] = organelleLetters[string.sub(stringCode, 1, 1)], - ["q"] = 0, - ["r"] = 0, - ["rotation"] = 0 - }} - - for i = 2, string.len(stringCode) do - local organelle = organelleLetters[string.sub(stringCode, i, i)] - q, r, rotation = getPosition(organelle, organelleList) - local newOrganelleData = { - ["name"] = organelle, - ["q"] = q, - ["r"] = r, - ["rotation"] = rotation - } - - table.insert(organelleList, newOrganelleData) - end - return organelleList -end diff --git a/scripts/microbe_stage/process_organelle.lua b/scripts/microbe_stage/process_organelle.lua deleted file mode 100644 index 66c22f3f07c..00000000000 --- a/scripts/microbe_stage/process_organelle.lua +++ /dev/null @@ -1,41 +0,0 @@ --------------------------------------------------------------------------------- --- Class for organelles capable of producing compounds. --- TODO: Make this handle adding and removing processes from the microbes. --------------------------------------------------------------------------------- -ProcessOrganelle = class( - OrganelleComponent, - -- Constructor - -- - -- @param arguments.colourChangeFactor - -- I got absolutely no idea - -- what this does :P. Also it doesn't seem to be used anymore - function(self, arguments, data) - - OrganelleComponent.create(self, arguments, data) - - --making sure this doesn't run when load() is called - if arguments == nil and data == nil then - return - end - - end -) - --- See organelle_component.lua for more information about the --- organelle component methods and the arguments they receive. - --- Adds a process to the processing organelle --- The organelle will distribute its capacity between processes --- --- @param process --- The process to add -function ProcessOrganelle:addProcess(process) - -- table.insert(self.processes, process) -end - -function ProcessOrganelle:storage() - return StorageContainer.new() -end - -function ProcessOrganelle:load(storage) -end diff --git a/scripts/microbe_stage/process_table.as b/scripts/microbe_stage/process_table.as new file mode 100644 index 00000000000..986bf330e3a --- /dev/null +++ b/scripts/microbe_stage/process_table.as @@ -0,0 +1,89 @@ + +//! Versions of processes that are used in OrganelleComponent +//! \todo It needs to be verified that this actually applies to the processor component +//! of a microbe in process_system.h +class TweakedProcess{ + + //! \param processName name of the process as it is in PROCESS_TABLE + TweakedProcess(const string &in processName, float tweakRate){ + + const BioProcess@ process; + if(!PROCESS_TABLE.get(processName, @process)){ + + // This helps debugging + printProcessTable(); + assert(false, "Tried to create TweakedProcess with invalid name: " + processName); + return; + } + + if(process is null){ + + assert(false, "TweakedProcess BioProcess with name is null: " + processName); + } + + _process.store(@process); + + if(this.process is null){ + + assert(false, "It's broken"); + } + + this.tweakRate = tweakRate; + } + + const BioProcess@ process { + get{ + const BioProcess@ obj; + _process.retrieve(@obj); + return obj; + } + } + + // TODO: is this worse or better performance than calling bioProcessRegistry().getTypeData + // any time the BioProcess is needed + private any _process; + + float tweakRate = 1.0; + + // The setup needs the process capacity for some reason + float capacity = 1.0f; +} + +dictionary PROCESS_TABLE; + +//! Sets up Processes for use +void setupProcesses(){ + + uint64 count = SimulationParameters::bioProcessRegistry().getSize(); + for(uint64 processId = 0; processId < count; ++processId){ + + const auto name = SimulationParameters::bioProcessRegistry(). + getInternalName(processId); + + // The handle needs to be used here to properly give the dictionary the handle value + @PROCESS_TABLE[name] = SimulationParameters::bioProcessRegistry(). + getTypeData(processId); + + // This is just a sanity check + // But keep this code for reference + const BioProcess@ process; + if(!PROCESS_TABLE.get(name, @process) || process is null){ + assert(false, "Logic for building PROCESS_TABLE broke"); + } + } + + // Uncomment to print process table for debugging + // printProcessTable(); +} + +void printProcessTable(){ + LOG_INFO("Registered processes:"); + auto keys = PROCESS_TABLE.getKeys(); + for(uint i = 0; i < keys.length(); ++i){ + + LOG_WRITE(keys[i]); + } + LOG_WRITE(""); +} + + diff --git a/scripts/microbe_stage/process_table.lua b/scripts/microbe_stage/process_table.lua deleted file mode 100644 index fbbf42ed207..00000000000 --- a/scripts/microbe_stage/process_table.lua +++ /dev/null @@ -1,68 +0,0 @@ ---[[ -Process atributes: - inputs: Table with the input compounds of this process, and its quantities. - - outputs: Table with the output compounds of this process, and its quantities. -]] - -processes = { - ["Respiration"] = { - inputs = { - glucose = 1, - oxygen = 6 - }, - - outputs = { - co2 = 6, - atp = 36 - } - }, - - ["AminoAcidSynthesis"] = { - inputs = { - glucose = 1, - ammonia = 1 - }, - - outputs = { - co2 = 1, - atp = 1, - aminoacids = 1 - } - }, - - ["FattyAcidSynthesis"] = { - inputs = { - glucose = 1, - ammonia = 1 - }, - - outputs = { - co2 = 1, - atp = 1, - fattyacids = 1 - } - }, - - ["OxyToxySynthesis"] = { - inputs = { - atp = 1, - oxygen = 3 - }, - - outputs = { - oxytoxy = 1 - } - }, - - ["Photosynthesis"] = { - inputs = { - co2 = 6 - }, - - outputs = { - glucose = 1, - oxygen = 6 - } - } -} diff --git a/scripts/microbe_stage/processor_organelle.as b/scripts/microbe_stage/processor_organelle.as new file mode 100644 index 00000000000..62369f65950 --- /dev/null +++ b/scripts/microbe_stage/processor_organelle.as @@ -0,0 +1,39 @@ +#include "organelle_component.as" + +//////////////////////////////////////////////////////////////////////////////// +// Class for organelles capable of producing compounds. +// TODO: Make this handle adding and removing processores from the microbes. +// Right now this does nothing! +//////////////////////////////////////////////////////////////////////////////// +class ProcessorOrganelle : OrganelleComponent{ + + // Constructor + // + // @param arguments.colourChangeFactor + // I got absolutely no idea + // what this does :P. Also it doesn't seem to be used anymore + ProcessorOrganelle(float colourChangeFactor = 1.0f){ + + } + + // // See organelle_component.lua for more information about the + // // organelle component methods and the arguments they receive. + + // // Adds a processor to the processoring organelle + // // The organelle will distribute its capacity between processores + // // + // // @param processor + // // The processor to add + // void ProcessorOrganelle.addProcessor(processor){ + // // table.insert(this.processes, processor) + // } + + void + onAddedToMicrobe( + ObjectID microbeEntity, + int q, int r, int rotation, + PlacedOrganelle@ organelle + ) override { + + } +} diff --git a/scripts/microbe_stage/setup.as b/scripts/microbe_stage/setup.as new file mode 100644 index 00000000000..60f6c2de558 --- /dev/null +++ b/scripts/microbe_stage/setup.as @@ -0,0 +1,485 @@ +#include "configs.as" + +// For system registering +#include "microbe.as" +#include "microbe_stage_hud.as" +#include "microbe_operations.as" +#include "microbe_ai.as" +#include "biome.as" + + +// This is a helper for calling all the setup functions at the same time +// This is the one called from C++ +void setupScriptsForWorld(CellStageWorld@ world){ + setupSpecies(world); + setupSystemsForWorld(world); + setupSpawnSystem(world); + setupSound(world); +} + +// This function should be the entry point for all player initial-species generation +// For now, it can go through the XML and instantiate all the species, but later this +// would be all procedural. +// Currently this goes through STARTER_MICROBES (defined in config.as) and makes entities with +// SpeciesComponents with the properties of the species +// The SpeciesSystem handles creating AI species +void setupSpecies(CellStageWorld@ world){ + + // Fail if compound registry is empty // + assert(SimulationParameters::compoundRegistry().getSize() > 0, + "Compound registry is empty"); + + auto keys = STARTER_MICROBES.getKeys(); + + for(uint i = 0; i < keys.length(); ++i){ + + const string name = keys[i]; + + MicrobeTemplate@ data = cast(STARTER_MICROBES[name]); + + ObjectID entity = Species::createSpecies(world, name, data); + + LOG_INFO("created starter microbe \"" + name + "\", species entity = " + entity); + } + + + LOG_INFO("setupSpecies created " + keys.length() + " species"); +} + +ScriptComponent@ MicrobeComponentFactory(GameWorld@ world){ + + return MicrobeComponent(); +} + +ScriptComponent@ MicrobeAIControllerComponentFactory(GameWorld@ world){ + + return MicrobeAIControllerComponent(); +} + +//! This function instantiates all script system types for a world +//! and registers all the microbe components that are defined in scripts to work +//! in a world +void setupSystemsForWorld(CellStageWorld@ world){ + + // Fail if compound registry is empty (hud system caches the compound ids on startup) // + assert(SimulationParameters::compoundRegistry().getSize() > 0, + "Compound registry is empty"); + + world.RegisterScriptComponentType("MicrobeComponent", @MicrobeComponentFactory); + world.RegisterScriptComponentType("MicrobeAIControllerComponent", + @MicrobeAIControllerComponentFactory); + + world.RegisterScriptSystem("MicrobeSystem", MicrobeSystem()); + world.RegisterScriptSystem("MicrobeStageHudSystem", MicrobeStageHudSystem()); + world.RegisterScriptSystem("SpeciesSystem", SpeciesSystem()); + world.RegisterScriptSystem("MicrobeAISystem", MicrobeAISystem()); + + // TODO: add the rest of the systems and component types that are defined in scripts here +} + + +//! This spawns the player +void setupPlayer(CellStageWorld@ world){ + assert(world !is null); + setRandomBiome(world); + GetThriveGame().playerData().lockedMap().addLock("Toxin"); + GetThriveGame().playerData().lockedMap().addLock("chloroplast"); + + ObjectID microbe = MicrobeOperations::spawnMicrobe(world, Float3(0, 0, 0), "Default", + false, PLAYER_NAME); + + assert(microbe != NULL_OBJECT, "Failed to spawn player cell"); + // TODO: powerupable + //microbe.collisionHandler.addCollisionGroup("powerupable"); + + GetThriveGame().playerData().setActiveCreature(microbe); + + // Testing spawning extra cell + MicrobeOperations::spawnMicrobe(world, Float3(10, 0, 0), "Default", + false, "extra player"); + + // // Test model spawn + // auto testModel = world.CreateEntity(); + + // auto position = world.Create_Position(testModel, Float3(5, 35, 5), + // Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), + // Ogre::Vector3(0, 1, 0))); + // auto sceneNode = world.Create_RenderNode(testModel); + // auto model = world.Create_Model(testModel, sceneNode.Node, "UnitCube.mesh"); +} + + +// TODO: move this somewhere +// This is called from c++ system PlayerMicrobeControlSystem +void applyCellMovementControl(GameWorld@ world, ObjectID entity, const Float3 &in movement, + const Float3 &in lookPosition) +{ + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(entity)); + + if(!microbeComponent.dead){ + + microbeComponent.facingTargetPoint = lookPosition; + microbeComponent.movementDirection = movement; + } +} + +void onReturnFromEditor(CellStageWorld@ world){ + + LOG_INFO("TODO: apply the changes and spawn a copy of the player species from " + "before the change"); + +} + +// TODO: also put these physics callback somewhere +void cellHitFloatingOrganelle(GameWorld@ world, ObjectID firstEntity, ObjectID secondEntity){ + + LOG_INFO("Cell hit a floating organelle: object ids: " + firstEntity + " and " + + secondEntity); + + // Determine which is the organelle + CellStageWorld@ asCellWorld = cast(world); + + auto model = asCellWorld.GetComponent_Model(firstEntity); + auto floatingEntity = firstEntity; + + // Cell doesn't have a model + if(model is null){ + + @model = asCellWorld.GetComponent_Model(secondEntity); + floatingEntity = secondEntity; + } + + // TODO: use this to detect stuff + LOG_INFO("Model: " + model.GraphicalObject.getMesh().getName()); + + world.QueueDestroyEntity(floatingEntity); +} + + + +// TODO: This should be moved somewhere else... +void createAgentCloud(CellStageWorld@ world, CompoundId compoundId, Float3 pos, + Float3 direction, float amount) +{ + auto normalizedDirection = direction.Normalize(); + auto agentEntity = world.CreateEntity(); + + // auto reactionHandler = CollisionComponent() + // reactionHandler.addCollisionGroup("agent") + auto position = world.Create_Position(agentEntity, pos + (direction * 1.5), + Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), + Ogre::Vector3(0, 1, 0))); + + auto rigidBody = world.Create_Physics(agentEntity, world, position, null); + + rigidBody.SetCollision(world.GetPhysicalWorld().CreateSphere(HEX_SIZE)); + rigidBody.CreatePhysicsBody(world.GetPhysicalWorld()); + // Agent + + rigidBody.CreatePlaneConstraint(world.GetPhysicalWorld(), Float3(0, 1, 0)); + + rigidBody.SetMass(0.001); + + // TODO: physics property applying here as well + // rigidBody.properties.friction = 0.4; + // rigidBody.properties.linearDamping = 0.4; + + // TODO: impulse or set velocity? + rigidBody.SetVelocity(normalizedDirection * AGENT_EMISSION_VELOCITY); + + auto sceneNode = world.Create_RenderNode(agentEntity); + auto model = world.Create_Model(agentEntity, sceneNode.Node, "oxytoxy.mesh"); + // Need to set the tint + model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); + + auto timedLifeComponent = world.Create_TimedLifeComponent(agentEntity, 2000); +} + + + + +//local void setSpawnablePhysics(ObjectID entity, Float3 pos, mesh, scale, collisionShape){ +// // Rigid body +// auto rigidBody = RigidBodyComponent() +// rigidBody.properties.friction = 0.2 +// rigidBody.properties.linearDamping = 0.8 + +// rigidBody.properties.shape = collisionShape +// rigidBody.setDynamicProperties( +// pos, +// Quaternion(Radian(Degree(math.random()*360)), Vector3(0, 0, 1)), +// Vector3(0, 0, 0), +// Vector3(0, 0, 0) +// ) +// rigidBody.properties.touch() +// entity.addComponent(rigidBody) +// // Scene node +// auto sceneNode = OgreSceneNodeComponent() +// sceneNode.meshName = mesh +// sceneNode.transform.scale = Vector3(scale, scale, scale) +// entity.addComponent(sceneNode) +// return entity +// } + + +// local void addEmitter2Entity(entity, compound){ +// auto compoundEmitter = CompoundEmitterComponent() +// entity.addComponent(compoundEmitter) +// compoundEmitter.emissionRadius = 1 +// compoundEmitter.maxInitialSpeed = 10 +// compoundEmitter.minInitialSpeed = 2 +// compoundEmitter.minEmissionAngle = Degree(0) +// compoundEmitter.maxEmissionAngle = Degree(360) +// compoundEmitter.particleLifeTime = 5000 +// auto timedEmitter = TimedCompoundEmitterComponent() +// timedEmitter.compoundId = CompoundRegistry.getCompoundId(compound) +// timedEmitter.particlesPerEmission = 1 +// timedEmitter.potencyPerParticle = 2.0 +// timedEmitter.emitInterval = 1000 +// entity.addComponent(timedEmitter) +// } + +//! AI species are spawned by Species in species_system +class PlayerSpeciesSpawner{ + PlayerSpeciesSpawner(const string &in speciesName){ + + this.species = speciesName; + } + + private string species; + + ObjectID factorySpawn(CellStageWorld@ world, Float3 pos){ + + LOG_INFO("Spawning a cell from player species: " + species); + return MicrobeOperations::spawnMicrobe(world, pos, species, + // ai controlled + true, + // No individual name (could be good for debugging) + ""); + } +} + + +ObjectID createToxin(CellStageWorld@ world, Float3 pos) +{ + + //toxins + ObjectID toxinEntity = world.CreateEntity(); + //LOG_INFO("toxin spawned at pos x"+ pos.X +"y"+ pos.Y +"z"+ pos.Z); + + auto position = world.Create_Position(toxinEntity, pos,Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)),Ogre::Vector3(0,1,0))); + + + auto renderNode = world.Create_RenderNode(toxinEntity); + renderNode.Scale = Float3(1, 1, 1); + renderNode.Marked = true; + renderNode.Node.setOrientation(Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)),Ogre::Vector3(0,1,1))); + renderNode.Node.setPosition(pos); + + + // Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)), + // Ogre::Vector3(0, 1, 0))); + + auto model = world.Create_Model(toxinEntity, renderNode.Node, "oxytoxy.mesh"); + // Need to set the tint + model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); + + auto rigidBody = world.Create_Physics(toxinEntity, world, position, null); + rigidBody.SetCollision(world.GetPhysicalWorld().CreateSphere(1)); + rigidBody.CreatePhysicsBody(world.GetPhysicalWorld(), + world.GetPhysicalMaterial("floatingOrganelle")); + rigidBody.CreatePlaneConstraint(world.GetPhysicalWorld(), Float3(0,1,0)); + rigidBody.SetMass(1.0f); + + + rigidBody.JumpTo(position); + + return toxinEntity; +} + +ObjectID createChloroplast(CellStageWorld@ world, Float3 pos) +{ + //cholroplasts + ObjectID chloroplastEntity = world.CreateEntity(); + //LOG_INFO("chloroplast spawned at pos x"+ pos.X +"y"+ pos.Y +"z"+ pos.Z); + auto position = world.Create_Position(chloroplastEntity, pos,Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)),Ogre::Vector3(0,1,1))); + + auto renderNode = world.Create_RenderNode(chloroplastEntity); + renderNode.Scale = Float3(1, 1, 1); + renderNode.Marked = true; + renderNode.Node.setOrientation(Ogre::Quaternion(Ogre::Degree(GetEngine().GetRandom().GetNumber(0, 360)),Ogre::Vector3(0,1,1))); + renderNode.Node.setPosition(pos); + + + + auto model = world.Create_Model(chloroplastEntity, renderNode.Node, "chloroplast.mesh"); + // Need to set the tint + model.GraphicalObject.setCustomParameter(1, Ogre::Vector4(1, 1, 1, 1)); + + auto rigidBody = world.Create_Physics(chloroplastEntity, world, position, null); + rigidBody.SetCollision(world.GetPhysicalWorld().CreateSphere(1)); + rigidBody.CreatePhysicsBody(world.GetPhysicalWorld(), + world.GetPhysicalMaterial("floatingOrganelle")); + rigidBody.CreatePlaneConstraint(world.GetPhysicalWorld(), Float3(0,1,0)); + rigidBody.SetMass(1.0f); + rigidBody.JumpTo(position); + + return chloroplastEntity; +} + +// TODO: the player species handling would be more logically placed if +// it was in SpeciesSystem, so move it there +void setupSpawnSystem(CellStageWorld@ world){ + //spawn code is here, if it isnt obvious by the name + SpawnSystem@ spawnSystem = world.GetSpawnSystem(); + + // Clouds are handled by biome.as + + LOG_INFO("setting up spawn information"); + + setupFloatingOrganelles(world); + + LOG_INFO("setting up player species to spawn"); + auto keys = STARTER_MICROBES.getKeys(); + for(uint n = 0; n < keys.length(); n++) + { + const string name = keys[n]; + + PlayerSpeciesSpawner@ spawner = PlayerSpeciesSpawner(name); + + SpawnFactoryFunc@ factory = SpawnFactoryFunc(spawner.factorySpawn); + + LOG_INFO("adding spawn player species: " + name); + + const auto spawnerId = spawnSystem.addSpawnType( + factory, DEFAULT_SPAWN_DENSITY, //spawnDensity should depend on population + MICROBE_SPAWN_RADIUS); + } +} + + + +//moved this over here fo rnow, its probabbly good to put "free spawning organelles" in their own function +void setupFloatingOrganelles(CellStageWorld@ world){ + LOG_INFO("setting up free floating organelles"); + SpawnSystem@ spawnSystem = world.GetSpawnSystem(); + + //spawn toxin and chloroplasts + const auto chloroId = spawnSystem.addSpawnType( + @createChloroplast, DEFAULT_SPAWN_DENSITY, + MICROBE_SPAWN_RADIUS); + + //toxins + const auto toxinId = spawnSystem.addSpawnType( + @createToxin, DEFAULT_SPAWN_DENSITY, + MICROBE_SPAWN_RADIUS); + + + + + // auto toxinOrganelleSpawnvoid = function(pos){ + // auto reactionHandler = CollisionComponent() + // reactionHandler.addCollisionGroup("powerup") + // powerupEntity.addComponent(reactionHandler) + // auto powerupComponent = PowerupComponent() + // // void name must be in configs.lua{ + // powerupComponent.setEffect("toxin_number") + // powerupEntity.addComponent(powerupComponent) + // return powerupEntity + // auto reactionHandler = CollisionComponent() + // reactionHandler.addCollisionGroup("powerup") + // powerupEntity.addComponent(reactionHandler) + + // auto powerupComponent = PowerupComponent() + // // void name must be in configs.lua{ + // powerupComponent.setEffect("chloroplast_number") + // powerupEntity.addComponent(powerupComponent) + // return powerupEntity + } + +void setupSound(CellStageWorld@ world){ + // auto ambientEntity = Entity("ambience", gameState.wrapper) + // auto soundSource = SoundSourceComponent() + // soundSource.ambientSoundSource = true + // soundSource.autoLoop = true + // soundSource.volumeMultiplier = 0.3 + // ambientEntity.addComponent(soundSource) + // // Gui effects + // auto guiSoundEntity = Entity("gui_sounds", gameState.wrapper) + // soundSource = SoundSourceComponent() + // soundSource.ambientSoundSource = true + // soundSource.autoLoop = false + // soundSource.volumeMultiplier = 1.0 + // guiSoundEntity.addComponent(soundSource) + // // Sound + // soundSource.addSound("button-hover-click", "soundeffects/gui/button-hover-click.ogg") + // soundSource.addSound("microbe-pickup-organelle", "soundeffects/microbe-pickup-organelle.ogg") + // auto listener = Entity("soundListener", gameState.wrapper) + // auto sceneNode = OgreSceneNodeComponent() + // listener.addComponent(sceneNode) +} + +// setupCompounds() +// setupProcesses() + +// local void createMicrobeStage(name){ +// return +// g_luaEngine.createGameState( +// name, +// { +// MicrobeReplacementSystem(), +// // SwitchGameStateSystem(), +// QuickSaveSystem(), +// // Microbe specific +// MicrobeSystem(), +// MicrobeCameraSystem(), +// MicrobeAISystem(), +// MicrobeControlSystem(), +// HudSystem(), +// TimedLifeSystem(), +// CompoundMovementSystem(), +// CompoundAbsorberSystem(), +// ProcessSystem(), +// //PopulationSystem(), +// PatchSystem(), +// SpeciesSystem(), +// // Physics +// RigidBodyInputSystem(), +// UpdatePhysicsSystem(), +// RigidBodyOutputSystem(), +// BulletToOgreSystem(), +// CollisionSystem(), +// // Microbe Specific again (order sensitive) +// setupSpawnSystem(), +// // Graphics +// OgreAddSceneNodeSystem(), +// OgreUpdateSceneNodeSystem(), +// OgreCameraSystem(), +// OgreLightSystem(), +// SkySystem(), +// OgreWorkspaceSystem(), +// OgreRemoveSceneNodeSystem(), +// RenderSystem(), +// MembraneSystem(), +// CompoundCloudSystem(), +// //AgentCloudSystem(), +// // Other +// SoundSourceSystem(), +// PowerupSystem(), +// CompoundEmitterSystem(), // Keep this after any logic that might eject compounds such that any entites that are queued for destruction will be destroyed after emitting. +// }, +// true, +// "MicrobeStage", +// function(gameState) +// setupBackground(gameState) +// setupCamera(gameState) +// setupCompoundClouds(gameState) +// setupSpecies(gameState) +// setupPlayer(gameState) +// setupSound(gameState) +// } +// ) +// } + + diff --git a/scripts/microbe_stage/setup.lua b/scripts/microbe_stage/setup.lua deleted file mode 100644 index 76e8c8e2fbb..00000000000 --- a/scripts/microbe_stage/setup.lua +++ /dev/null @@ -1,435 +0,0 @@ -CLOUD_SPAWN_RADIUS = 75 - -BACTERIA_SPAWN_RADIUS = 87 -BACTERIA_SPAWN_DENSITY = 1/4000 - -POWERUP_SPAWN_RADIUS = 85 -MICROBE_SPAWN_RADIUS = 85 - -AGENT_EMISSION_VELOCITY = 20 - -local function setupBackground(gameState) - setRandomBiome(gameState) -end - -local function setupCamera(gameState) - local entity = Entity.new(CAMERA_NAME, gameState.wrapper) - -- Camera - local camera = OgreCameraComponent.new("camera") - camera.properties.nearClipDistance = 5 - camera.properties.offset = Vector3(0, 0, 30) - camera.properties:touch() - entity:addComponent(camera) - -- Scene node - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.transform.position.z = 30 - sceneNode.transform:touch() - entity:addComponent(sceneNode) - -- Light - local light = OgreLightComponent.new() - light:setRange(200) - entity:addComponent(light) - -- Workspace - local workspaceEntity = Entity.new(gameState.wrapper) - local workspaceComponent = OgreWorkspaceComponent.new("thrive_default") - workspaceComponent.properties.cameraEntity = entity - workspaceComponent.properties.position = 0 - workspaceComponent.properties:touch() - workspaceEntity:addComponent(workspaceComponent) -end - -local function setupCompounds() - - local ordered_keys = {} - - for k in pairs(compoundTable) do - table.insert(ordered_keys, k) - end - - table.sort(ordered_keys) - for i = 1, #ordered_keys do - local k, v = ordered_keys[i], compoundTable[ ordered_keys[i] ] - CompoundRegistry.registerCompoundType(k, v["name"], "placeholder.mesh", 1.0, v["isUseful"] == true, v["volume"]) - end - CompoundRegistry.loadFromLua({}, agents) -end - -local function setupCompoundClouds(gameState) - for compoundName, compoundInfo in pairs(compoundTable) do - if compoundInfo.isCloud then - local compoundId = CompoundRegistry.getCompoundId(compoundName) - local entity = Entity.new("compound_cloud_" .. compoundName, gameState.wrapper) - local compoundCloud = CompoundCloudComponent.new() - local colour = compoundInfo.colour - compoundCloud:initialize(compoundId, colour.r, colour.g, colour.b) - entity:addComponent(compoundCloud) - end - end -end - -local function setupProcesses() - assert(processes) - BioProcessRegistry.loadFromLua(processes) -end - -function setupSpecies(gameState) - --[[ - This function should be the entry point for all initial-species generation - For now, it can go through the XML and instantiate all the species, but later this - would be all procedural. - Together with the mutate function, these would be the only ways species are created - ]] - - for name, data in pairs(starter_microbes) do - speciesEntity = Entity.new(name, gameState.wrapper) - speciesComponent = SpeciesComponent.new(name) - speciesEntity:addComponent(speciesComponent) - for i, organelle in pairs(data.organelles) do - local org = {} - org.name = organelle.name - org.q = organelle.q - org.r = organelle.r - org.rotation = organelle.rotation - speciesComponent.organelles[i] = org - end - processorComponent = ProcessorComponent.new() - speciesEntity:addComponent(processorComponent) - speciesComponent.colour = Vector3(data.colour.r, data.colour.g, data.colour.b) - - -- iterates over all compounds, and sets amounts and priorities - for _, compoundID in pairs(CompoundRegistry.getCompoundList()) do - compound = CompoundRegistry.getCompoundInternalName(compoundID) - compoundData = data.compounds[compound] - if compoundData ~= nil then - amount = compoundData.amount - -- priority = compoundData.priority - speciesComponent.avgCompoundAmounts["" .. compoundID] = amount - -- speciesComponent.compoundPriorities[compoundID] = priority - end - end - - local capacities = {} - for _, organelle in pairs(data.organelles) do - if organelleTable[organelle.name] ~= nil then - if organelleTable[organelle.name]["processes"] ~= nil then - for process, capacity in pairs(organelleTable[organelle.name]["processes"]) do - if capacities[process] == nil then - capacities[process] = 0 - end - capacities[process] = capacities[process] + capacity - end - end - end - end - for _, bioProcessId in pairs(BioProcessRegistry.getList()) do - local name = BioProcessRegistry.getInternalName(bioProcessId) - if capacities[name] ~= nil then - processorComponent:setCapacity(bioProcessId, capacities[name]) - -- else - -- processorComponent:setCapacity(bioProcessId, 0) - end - end - end -end - -function microbeSpawnFunctionGeneric(pos, speciesName, aiControlled, individualName, gameState) - return spawnMicrobe(pos, speciesName, aiControlled, individualName) -end - --- speciesName decides the template to use, while individualName is used for referencing the instance -function spawnMicrobe(pos, speciesName, aiControlled, individualName) - assert(isNotEmpty(speciesName)) - - local processor = getComponent(speciesName, g_luaEngine.currentGameState, ProcessorComponent) - assert(processor ~= nil, "Crashing the game because species '" .. speciesName .. - "' doesn't have a processor component") - - local microbeEntity = MicrobeSystem.createMicrobeEntity(individualName, aiControlled, speciesName, false) - local rigidBodyComponent = getComponent(microbeEntity, RigidBodyComponent) - - if pos ~= nil then - rigidBodyComponent:setDynamicProperties( - pos, -- Position - Quaternion.new(Radian.new(Degree(0)), Vector3(1, 0, 0)), -- Orientation - Vector3(0, 0, 0), -- Linear velocity - Vector3(0, 0, 0) -- Angular velocity - ) - end - return microbeEntity -end - -function setSpawnablePhysics(entity, pos, mesh, scale, collisionShape) - -- Rigid body - local rigidBody = RigidBodyComponent.new() - rigidBody.properties.friction = 0.2 - rigidBody.properties.linearDamping = 0.8 - - rigidBody.properties.shape = collisionShape - rigidBody:setDynamicProperties( - pos, - Quaternion.new(Radian.new(Degree(math.random()*360)), Vector3(0, 0, 1)), - Vector3(0, 0, 0), - Vector3(0, 0, 0) - ) - rigidBody.properties:touch() - entity:addComponent(rigidBody) - -- Scene node - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.meshName = mesh - sceneNode.transform.scale = Vector3(scale, scale, scale) - entity:addComponent(sceneNode) - return entity -end - -function createCompoundCloud(compoundName, x, y, amount) - if amount == nil then amount = currentBiome.compounds[compoundName] end - if amount == nil then amount = 0 end - - if compoundTable[compoundName] and compoundTable[compoundName].isCloud then - -- addCloud requires integer arguments - x = math.floor(x) - y = math.floor(y) - getComponent("compound_cloud_" .. compoundName, - g_luaEngine.currentGameState, CompoundCloudComponent - ):addCloud(amount, x, y) - end - - -- The spawn system expects an entity. - return Entity.new(g_luaEngine.currentGameState.wrapper) -end - -function createAgentCloud(compoundId, x, y, direction, amount) - local normalizedDirection = direction - normalizedDirection:normalise() - local agentEntity = Entity.new(g_luaEngine.currentGameState.wrapper) - - local reactionHandler = CollisionComponent.new() - reactionHandler:addCollisionGroup("agent") - agentEntity:addComponent(reactionHandler) - - local rigidBody = RigidBodyComponent.new() - rigidBody.properties.mass = 0.001 - rigidBody.properties.friction = 0.4 - rigidBody.properties.linearDamping = 0.4 - rigidBody.properties.shape = SphereShape.new(HEX_SIZE) - rigidBody:setDynamicProperties( - Vector3(x, y, 0) + direction * 1.5, - Quaternion.new(Radian.new(Degree(math.random()*360)), Vector3(0, 0, 1)), - normalizedDirection * AGENT_EMISSION_VELOCITY, - Vector3(0, 0, 0) - ) - rigidBody.properties:touch() - agentEntity:addComponent(rigidBody) - - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.meshName = "oxytoxy.mesh" - agentEntity:addComponent(sceneNode) - - local timedLifeComponent = TimedLifeComponent.new() - timedLifeComponent.timeToLive = 2000 - agentEntity:addComponent(timedLifeComponent) -end - -local function addEmitter2Entity(entity, compound) - local compoundEmitter = CompoundEmitterComponent.new() - entity:addComponent(compoundEmitter) - compoundEmitter.emissionRadius = 1 - compoundEmitter.maxInitialSpeed = 10 - compoundEmitter.minInitialSpeed = 2 - compoundEmitter.minEmissionAngle = Degree(0) - compoundEmitter.maxEmissionAngle = Degree(360) - compoundEmitter.particleLifeTime = 5000 - local timedEmitter = TimedCompoundEmitterComponent.new() - timedEmitter.compoundId = CompoundRegistry.getCompoundId(compound) - timedEmitter.particlesPerEmission = 1 - timedEmitter.potencyPerParticle = 2.0 - timedEmitter.emitInterval = 1000 - entity:addComponent(timedEmitter) -end - -local function setupSpawnSystem(gameState) - gSpawnSystem = SpawnSystem.new() - - local toxinOrganelleSpawnFunction = function(pos) - powerupEntity = Entity.new(g_luaEngine.currentGameState.wrapper) - setSpawnablePhysics(powerupEntity, pos, "AgentVacuole.mesh", 0.9, - SphereShape.new(HEX_SIZE)) - - local reactionHandler = CollisionComponent.new() - reactionHandler:addCollisionGroup("powerup") - powerupEntity:addComponent(reactionHandler) - - local powerupComponent = PowerupComponent.new() - -- Function name must be in configs.lua - powerupComponent:setEffect("toxinEffect") - powerupEntity:addComponent(powerupComponent) - return powerupEntity - end - local ChloroplastOrganelleSpawnFunction = function(pos) - powerupEntity = Entity.new(g_luaEngine.currentGameState.wrapper) - setSpawnablePhysics(powerupEntity, pos, "chloroplast.mesh", 0.9, - SphereShape.new(HEX_SIZE)) - - local reactionHandler = CollisionComponent.new() - reactionHandler:addCollisionGroup("powerup") - powerupEntity:addComponent(reactionHandler) - - local powerupComponent = PowerupComponent.new() - -- Function name must be in configs.lua - powerupComponent:setEffect("chloroplastEffect") - powerupEntity:addComponent(powerupComponent) - return powerupEntity - end - - compoundSpawnTypes = {} - for compoundName, compoundInfo in pairs(compoundTable) do - if compoundInfo.isCloud then - local spawnCloud = function(pos) - return createCompoundCloud(compoundName, pos.x, pos.y) - end - - compoundSpawnTypes[compoundName] = gSpawnSystem:addSpawnType(spawnCloud, 1/10000, CLOUD_SPAWN_RADIUS) -- Placeholder, the real one is set in biome.lua - end - end - - for bacteriaName, _ in pairs(bacteriaTable) do - local spawnBacteria = function(pos) - return Bacterium.createBacterium(bacteriaName, pos, g_luaEngine.currentGameState) - end - - -- TODO: make the density change on biome change. - gSpawnSystem:addSpawnType(spawnBacteria, BACTERIA_SPAWN_DENSITY, BACTERIA_SPAWN_RADIUS) - end - - gSpawnSystem:addSpawnType(toxinOrganelleSpawnFunction, 1/17000, POWERUP_SPAWN_RADIUS) - gSpawnSystem:addSpawnType(ChloroplastOrganelleSpawnFunction, 1/12000, POWERUP_SPAWN_RADIUS) - - for name, species in pairs(starter_microbes) do - - assert(isNotEmpty(name)) - assert(species) - - gSpawnSystem:addSpawnType( - function(pos) - return microbeSpawnFunctionGeneric(pos, name, true, nil, - g_luaEngine.currentGameState) - end, - species.spawnDensity, MICROBE_SPAWN_RADIUS) - end - - return gSpawnSystem -end - -local function setupPlayer() - local microbeEntity = spawnMicrobe(nil, "Default", false, PLAYER_NAME) - local collisionHandlerComponent = getComponent(microbeEntity, CollisionComponent) - - collisionHandlerComponent:addCollisionGroup("powerupable") - Engine:playerData():lockedMap():addLock("Toxin") - Engine:playerData():lockedMap():addLock("chloroplast") - Engine:playerData():setActiveCreature(microbeEntity, g_luaEngine.currentGameState.wrapper) -end - -local function setupSound(gameState) - local ambientEntity = Entity.new("ambience", gameState.wrapper) - local soundSource = SoundSourceComponent.new() - soundSource.ambientSoundSource = true - soundSource.autoLoop = true - soundSource.volumeMultiplier = 0.3 - ambientEntity:addComponent(soundSource) - -- Sound - soundSource:addSound("microbe-theme-1", "microbe-theme-1.ogg") - soundSource:addSound("microbe-theme-3", "microbe-theme-3.ogg") - soundSource:addSound("microbe-theme-4", "microbe-theme-4.ogg") - soundSource:addSound("microbe-theme-5", "microbe-theme-5.ogg") - soundSource:addSound("microbe-theme-6", "microbe-theme-6.ogg") - soundSource:addSound("microbe-theme-7", "microbe-theme-7.ogg") - local ambientEntity2 = Entity.new("ambience2", gameState.wrapper) - local soundSource = SoundSourceComponent.new() - soundSource.volumeMultiplier = 0.1 - soundSource.ambientSoundSource = true - ambientSound = soundSource:addSound("microbe-ambient", "soundeffects/microbe-ambience.ogg") - soundSource.autoLoop = true - ambientEntity2:addComponent(soundSource) - -- Gui effects - local guiSoundEntity = Entity.new("gui_sounds", gameState.wrapper) - soundSource = SoundSourceComponent.new() - soundSource.ambientSoundSource = true - soundSource.autoLoop = false - soundSource.volumeMultiplier = 1.0 - guiSoundEntity:addComponent(soundSource) - -- Sound - soundSource:addSound("button-hover-click", "soundeffects/gui/button-hover-click.ogg") - soundSource:addSound("microbe-pickup-organelle", "soundeffects/microbe-pickup-organelle.ogg") - local listener = Entity.new("soundListener", gameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - listener:addComponent(sceneNode) -end - -setupCompounds() -setupProcesses() - -local function createMicrobeStage(name) - return - g_luaEngine:createGameState( - name, - { - MicrobeReplacementSystem.new(), - -- SwitchGameStateSystem.new(), - QuickSaveSystem.new(), - -- Microbe specific - MicrobeSystem.new(), - MicrobeCameraSystem.new(), - MicrobeAISystem.new(), - MicrobeControlSystem.new(), - HudSystem.new(), - TimedLifeSystem.new(), - CompoundMovementSystem.new(), - CompoundAbsorberSystem.new(), - ProcessSystem.new(), - --PopulationSystem.new(), - PatchSystem.new(), - SpeciesSystem.new(), - BacteriaSystem.new(), - -- Physics - RigidBodyInputSystem.new(), - UpdatePhysicsSystem.new(), - RigidBodyOutputSystem.new(), - BulletToOgreSystem.new(), - CollisionSystem.new(), - -- Microbe Specific again (order sensitive) - setupSpawnSystem(), - -- Graphics - OgreAddSceneNodeSystem.new(), - OgreUpdateSceneNodeSystem.new(), - OgreCameraSystem.new(), - OgreLightSystem.new(), - SkySystem.new(), - OgreWorkspaceSystem.new(), - OgreRemoveSceneNodeSystem.new(), - RenderSystem.new(), - MembraneSystem.new(), - CompoundCloudSystem.new(), - --AgentCloudSystem.new(), - -- Other - SoundSourceSystem.new(), - PowerupSystem.new(), - CompoundEmitterSystem.new(), -- Keep this after any logic that might eject compounds such that any entites that are queued for destruction will be destroyed after emitting. - }, - true, - "MicrobeStage", - function(gameState) - setupBackground(gameState) - setupCamera(gameState) - setupCompoundClouds(gameState) - setupSpecies(gameState) - setupPlayer() - initBacterialSpecies(gameState) - setupSound(gameState) - end - ) -end - -GameState.MICROBE = createMicrobeStage("microbe") ---GameState.MICROBE_ALTERNATE = createMicrobeStage("microbe_alternate") ---Engine:setCurrentGameState(GameState.MICROBE) diff --git a/scripts/microbe_stage/species_system.as b/scripts/microbe_stage/species_system.as new file mode 100644 index 00000000000..44f8ca129d3 --- /dev/null +++ b/scripts/microbe_stage/species_system.as @@ -0,0 +1,743 @@ +#include "organelle_table.as" +#include "microbe_operations.as" +#include "procedural_microbes.as" + +float randomColourChannel(){ + return GetEngine().GetRandom().GetNumber(MIN_COLOR, MAX_COLOR); +} + +float randomOpacity(){ + return GetEngine().GetRandom().GetNumber(MIN_OPACITY, MAX_OPACITY); +} + + +Float4 randomColour(float opaqueness = randomOpacity()){ + return Float4(randomColourChannel(), randomColourChannel(), randomColourChannel(), + opaqueness); +} + + +const dictionary DEFAULT_INITIAL_COMPOUNDS = + { + {"atp", InitialCompound(60, 10)}, + {"glucose", InitialCompound(10)}, + {"reproductase", InitialCompound(0, 8)}, + {"oxygen", InitialCompound(10)}, + {"oxytoxy", InitialCompound(1)} + }; + +string randomSpeciesName(){ + return "Species_" + formatInt(GetEngine().GetRandom().GetNumber(0, 10000)); + // Gotta use the latin names (But they aren't used?) +} + +// Bacteria also need names +string randomBacteriaName(){ + return "Bacteria_" + formatInt(GetEngine().GetRandom().GetNumber(0, 10000)); +} + +//////////////////////////////////////////////////////////////////////////////// +// Species class +// +// Class for representing an individual species (This is stored in the world's +// SpeciesSystem instance) +//////////////////////////////////////////////////////////////////////////////// +//! \todo This should be moved into the SpeciesComponent class to simplify things +//now what is the best way to seperate bacteria from this... +class Species{ + //! Constructor for automatically creating a random species + Species(CellStageWorld@ world, bool isBacteria){ + this.isBacteria=isBacteria; + if (!isBacteria) + { + name = randomSpeciesName(); + auto stringSize = GetEngine().GetRandom().GetNumber(MIN_INITIAL_LENGTH, + MAX_INITIAL_LENGTH); + + //it should always have a nucleus and a cytoplasm. + stringCode = getOrganelleDefinition("nucleus").gene + + getOrganelleDefinition("cytoplasm").gene; + + for(int i = 0; i < stringSize; ++i){ + this.stringCode += getRandomLetter(); + } + + commonConstructor(world); + + colour = randomColour(); + + this.setupSpawn(world); + } + else{ + // We are creating a bacteria right now + generateBacteria(world); + } + } + + ~Species(){ + + if(templateEntity != NULL_OBJECT){ + + LOG_ERROR("Species object not extinguish()ed before destructor, doing that now"); + extinguish(); + } + } + + // Creates a mutated version of the species and reduces the species population by half + Species(Species@ parent, CellStageWorld@ world, bool isBacteria){ + this.isBacteria=isBacteria; + if (!isBacteria) + { + name = randomSpeciesName(); + //chance of new color needs to be low + if (GetEngine().GetRandom().GetNumber(0,100)==1) + { + LOG_INFO("New Clade"); + //we can do more fun stuff here later + this.colour = randomColour(); + } + else + { + this.colour = parent.colour; + } + this.population = int(floor(parent.population / 2.f)); + parent.population = int(ceil(parent.population / 2.f)); + this.stringCode = Species::mutate(parent.stringCode); + + commonConstructor(world); + + this.setupSpawn(world); + } + else + { + mutateBacteria(parent,world); + } + } + + private void commonConstructor(CellStageWorld@ world){ + + @forWorld = world; + + auto organelles = positionOrganelles(stringCode); + + templateEntity = Species::createSpecies(forWorld, this.name, organelles, this.colour, this.isBacteria, + DEFAULT_INITIAL_COMPOUNDS); + } + + //delete a species + void extinguish(){ + if(forWorld !is null){ + LOG_INFO("Species " + name + " has been extinguished"); + forWorld.GetSpawnSystem().removeSpawnType(this.id); + //this.template.destroy() //game crashes if i do that. + // Let's hope this doesn't crash then + if(templateEntity != NULL_OBJECT){ + forWorld.DestroyEntity(templateEntity); + templateEntity = NULL_OBJECT; + } + + @forWorld = null; + } + } + + ObjectID factorySpawn(CellStageWorld@ world, Float3 pos){ + + LOG_INFO("New member of species spawned: " + this.name); + return MicrobeOperations::spawnMicrobe(world, pos, this.name, + // ai controlled + true, + // No individual name (could be good for debugging) + ""); + } + + ObjectID bacteriaColonySpawn(CellStageWorld@ world, Float3 pos){ + LOG_INFO("New colony of species spawned: " + this.name); + Float3 curSpawn = Float3(GetEngine().GetRandom().GetNumber(1,10),0,GetEngine().GetRandom().GetNumber(1,10)); + //two kinds of colonies are supported, line colonies and clump colonies + + if (GetEngine().GetRandom().GetNumber(0,4) < 2) + { + //clump + for(int i = 0; i < GetEngine().GetRandom().GetNumber(1,5); ++i){ + //dont spawn them on top of each other because it causes them to bounce around and lag + MicrobeOperations::spawnBacteria(world, pos+curSpawn, this.name,true,"",true); + curSpawn = curSpawn + Float3(GetEngine().GetRandom().GetNumber(-10,10),0,GetEngine().GetRandom().GetNumber(-10,10)); + } + } + else + { + //line + for(int i = 0; i < GetEngine().GetRandom().GetNumber(1,5); ++i){ + //dont spawn them on top of each other because it causes them to bounce around and lag + MicrobeOperations::spawnBacteria(world, pos+curSpawn, this.name,true,"",true); + curSpawn = curSpawn + Float3(GetEngine().GetRandom().GetNumber(1,10),0,GetEngine().GetRandom().GetNumber(1,10)); + } + } + return MicrobeOperations::spawnBacteria(world, pos, this.name,true,"",false); + + } + + + void setupBacteriaSpawn(CellStageWorld@ world){ + + assert(world is forWorld, "Wrong world passed to setupSpawn"); + + spawningEnabled = true; + + SpawnFactoryFunc@ factory = SpawnFactoryFunc(this.bacteriaColonySpawn); + + // And register new + LOG_INFO("Registering bacteria to spawn: " + name); + this.id = forWorld.GetSpawnSystem().addSpawnType( + factory, DEFAULT_SPAWN_DENSITY, //spawnDensity should depend on population + MICROBE_SPAWN_RADIUS); + } + + //sets up the spawn of the species + // This may only be called once. Otherwise old spawn types are left active + void setupSpawn(CellStageWorld@ world){ + + assert(world is forWorld, "Wrong world passed to setupSpawn"); + + spawningEnabled = true; + + SpawnFactoryFunc@ factory = SpawnFactoryFunc(this.factorySpawn); + + // And register new + LOG_INFO("Registering species to spawn: " + name); + this.id = forWorld.GetSpawnSystem().addSpawnType( + factory, DEFAULT_SPAWN_DENSITY, //spawnDensity should depend on population + MICROBE_SPAWN_RADIUS); + } + + void generateBacteria(CellStageWorld@ world){ + name = randomBacteriaName(); + //bacteria are tiny + auto stringSize = GetEngine().GetRandom().GetNumber(0,3); + //it should always have a nucleus and a cytoplasm. + //bacteria will randomly have 1 of 3 organelles right now, chlorolast, mitochondria, or toxin, adding pure cytoplasm bacteria aswell for variety + switch( GetEngine().GetRandom().GetNumber(1,5)) + { + case 1: + stringCode = getOrganelleDefinition("cytoplasm").gene; + break; + case 2: + stringCode = getOrganelleDefinition("respiartoryProteins").gene; + break; + case 3: + stringCode = getOrganelleDefinition("photosyntheticProteins").gene; + break; + case 4: + stringCode = getOrganelleDefinition("oxytoxyProteins").gene; + break; + default: + stringCode = getOrganelleDefinition("cytoplasm").gene; + break; + } + + string chosenType= stringCode; + for(int i = 0; i < stringSize; ++i){ + this.stringCode += chosenType; + } + + commonConstructor(world); + colour = randomColour(); + this.setupBacteriaSpawn(world); + } + + void mutateBacteria(Species@ parent, CellStageWorld@ world){ + name = randomBacteriaName(); + if (GetEngine().GetRandom().GetNumber(0,100)==1) + { + LOG_INFO("New Clade of bacteria"); + //we can do more fun stuff here later + this.colour = randomColour(); + } + else + { + this.colour = parent.colour; + } + this.population = int(floor(parent.population / 2.f)); + parent.population = int(ceil(parent.population / 2.f)); + //right now all they will do is get new colors sometimes + //this.stringCode = Species::mutate(parent.stringCode); + + commonConstructor(world); + + this.setupBacteriaSpawn(world); + } + //updates the population count of the species + void updatePopulation(){ + //TODO: + //fill me + //with code + this.population += GetEngine().GetRandom().GetNumber(-200, 200); + } + + string name; + bool isBacteria; + string stringCode; + int population = INITIAL_POPULATION; + Float4 colour = randomColour(); + + //! The species entity that has this species' SpeciesComponent + ObjectID templateEntity = NULL_OBJECT; + + SpawnerTypeId id; + bool spawningEnabled = false; + CellStageWorld@ forWorld; +} +//////////////////////////////////////////////////////////////////////////////// +// SpeciesSystem +// +// System for estimating and simulating population count for various species +//////////////////////////////////////////////////////////////////////////////// + +//How big is a newly created species's population. +const auto INITIAL_POPULATION = 2000; + +//how much time does it take for the simulation to update. +const auto SPECIES_SIM_INTERVAL = 20000; + +//if a specie's population goes below this it goes extinct. +const auto MIN_POP_SIZE = 100; + +//if a specie's population goes above this it gets split in half and a +//new mutated species apears. +const auto MAX_POP_SIZE = 5000; + +//the amount of species at the start of the microbe stage (not counting Default/Player) +const auto INITIAL_SPECIES = 7; + +//the amount of bacteria +const auto INITIAL_BACTERIA = 4; + +//if there are more species than this then all species get their population reduced by half +const auto MAX_SPECIES = 15; + +//if there are more bacteria than this then all species get their population reduced by half +const auto MAX_BACTERIA = 6; + +//if there are less species than this creates new ones. +const auto MIN_SPECIES = 3; + +//if there are less species than this creates new ones. +const auto MIN_BACTERIA = 2; + +//! Updates the species's population and creates new ones. And keeps track of Species objects +class SpeciesSystem : ScriptSystem{ + + void Init(GameWorld@ w){ + + @this.world = cast(w); + assert(this.world !is null, "SpeciesSystem expected CellStageWorld"); + + // This was commented out in the Lua version... TODO: check that this works + //can confirtm, it crashes here - Untrustedlife + // This is needed to actually have AI species in the world + for(int i = 0; i < INITIAL_SPECIES; ++i){ + createSpecies(); + } + + //generate bacteria aswell + for(int i = 0; i < INITIAL_BACTERIA; ++i){ + createBacterium(); + } + } + + void Release(){ + // Destroy all species to stop complaints that they aren't extinguished + resetAutoEvo(); + } + + void Run(){ + while(this.timeSinceLastCycle > SPECIES_SIM_INTERVAL){ + + this.timeSinceLastCycle -= SPECIES_SIM_INTERVAL; + + //update population numbers and split/extinct species as needed + auto numberOfSpecies = species.length(); + for(uint i = 0; i < numberOfSpecies; ++i){ + //traversing the population backwards to avoid + //"chopping down the branch i'm sitting in" + auto index = numberOfSpecies - i; + + auto currentSpecies = species[index]; + currentSpecies.updatePopulation(); + auto population = currentSpecies.population; + + //reproduction/mutation + if(population > MAX_POP_SIZE){ + auto newSpecies = Species(currentSpecies, world, currentSpecies.isBacteria); + species.insertLast(newSpecies); + LOG_INFO("Species " + currentSpecies.name + " split off a child species:" + + newSpecies.name); + } + + //extinction + if(population < MIN_POP_SIZE){ + LOG_INFO("Species " + currentSpecies.name + " went extinct"); + currentSpecies.extinguish(); + species.removeAt(index); + } + } + + //new species + while(species.length() < MIN_SPECIES){ + LOG_INFO("Creating new species as there's too few"); + createSpecies(); + } + + //TODO: new bacteria they require their own list or they may be out competed by microbes + //while(species.length() < MIN_SPECIES){ + // LOG_INFO("Creating new bacteria as there's too few"); + // createBacteria(); + //} + + //mass extinction + if(species.length() > MAX_SPECIES+INITIAL_BACTERIA){ + + LOG_INFO("Mass extinction time"); + doMassExtinction(); + } + } + } + + void Clear(){} + + void CreateAndDestroyNodes(){} + + + void resetAutoEvo(){ + + for(uint i = 0; i < species.length(); ++i){ + + species[i].extinguish(); + } + + species.resize(0); + } + + void doMassExtinction(){ + for(uint i = 0; i < species.length(); ++i){ + species[i].population /= 2; + } + } + + //! Adds a new AI species + private void createSpecies(){ + auto newSpecies = Species(world, false); + species.insertLast(newSpecies); + } + + //! Adds a new AI bacterium + private void createBacterium(){ + auto newSpecies = Species(world, true); + species.insertLast(newSpecies); + } + + private int timeSinceLastCycle = 0; + private array species; + private CellStageWorld@ world; +} + +//! \param updateSpecies will be modified to match the organelles of the microbe +void updateSpeciesFromMicrobe(CellStageWorld@ world, ObjectID microbeEntity, + SpeciesComponent@ updateSpecies +) { + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + auto membraneComponent = world.GetComponent_MembraneComponent(microbeEntity); + + // this.name = microbeComponent.speciesName + updateSpecies.colour = membraneComponent.getColour(); + + updateSpecies.organelles.resize(0); + + // Create species' organelle data + for(uint i = 0; i < microbeComponent.organelles.length(); ++i){ + + updateSpecies.organelles.insertLast(PlacedOrganelle(microbeComponent.organelles[i])); + } + + // This microbes compound amounts will be the new population average. + updateSpecies.avgCompoundAmounts = {}; + + uint64 compoundCount = SimulationParameters::compoundRegistry().getSize(); + for(uint compoundId = 0; compoundId < compoundCount; ++compoundId){ + + auto amount = MicrobeOperations::getCompoundAmount(world, microbeEntity, compoundId); + updateSpecies.avgCompoundAmounts[formatUInt(compoundId)] = InitialCompound(amount); + } + // TODO: make this update the ProcessorComponent based on microbe thresholds +} + +// TODO: make sure this is called from somewhere +void initProcessorComponent(CellStageWorld@ world, ObjectID entity, + SpeciesComponent@ speciesComponent +) { + assert(world.GetComponent_SpeciesComponent(entity) is speciesComponent, + "Wrong speciesComponent passed to initProcessorComponent"); + + assert(speciesComponent.organelles.length() > 0, "initProcessorComponent given a " + "species that has no organelles"); + + auto pc = world.GetComponent_ProcessorComponent(entity); + + if(pc is null){ + + @pc = world.Create_ProcessorComponent(entity); + } + + dictionary capacities = {}; + for(uint i = 0; i < speciesComponent.organelles.length(); ++i){ + auto@ processes = cast(speciesComponent.organelles[i]). + organelle.processes; + + for(uint a = 0; a < processes.length(); ++a){ + + auto@ process = processes[a]; + auto name = process.process.internalName; + + if(!capacities.exists(name)){ + capacities[name] = 0; + } + + auto dictValue = capacities[name]; + dictValue = float(dictValue) + process.capacity; + } + } + + uint64 processCount = SimulationParameters::bioProcessRegistry().getSize(); + for(uint bioProcessID = 0; bioProcessID < processCount; ++bioProcessID){ + auto name = SimulationParameters::bioProcessRegistry().getInternalName(bioProcessID); + if(capacities.exists(name)){ + pc.setCapacity(bioProcessID, float(capacities[name])); + } + } +} + + +namespace Species{ +// Given a newly-created microbe, this sets the organelles and all other +// species-specific microbe data like agent codes, for example. +//! Brief applies template to a microbe entity making sure it has all +//! the correct organelle components +void applyTemplate(CellStageWorld@ world, ObjectID microbe, SpeciesComponent@ species){ + + // Fail if the species is not set up + assert(species.organelles.length() > 0, "Error can't apply uninitialized species " + + "template: " + species.name); + + MicrobeComponent@ microbeComponent = cast( + world.GetScriptComponentHolder("MicrobeComponent").Find(microbe)); + + // TODO: Make this also set the microbe's ProcessorComponent + microbeComponent.speciesName = species.name; + MicrobeOperations::setMembraneColour(world, microbe, species.colour); + + restoreOrganelleLayout(world, microbe, microbeComponent, species); + + // TODO: should the compound amounts be reset before this? + auto ids = species.avgCompoundAmounts.getKeys(); + for(uint i = 0; i < ids.length(); ++i){ + CompoundId compoundId = parseUInt(ids[i]); + InitialCompound amount = InitialCompound(species.avgCompoundAmounts[ids[i]]); + + if(amount.amount != 0){ + MicrobeOperations::storeCompound(world, microbe, compoundId, amount.amount, false); + } + } +} + +void restoreOrganelleLayout(CellStageWorld@ world, ObjectID microbeEntity, + MicrobeComponent@ microbeComponent, SpeciesComponent@ species +) { + // delete the the previous organelles. + while(microbeComponent.organelles.length() > 0){ + + auto organelle = microbeComponent.organelles[microbeComponent.organelles.length() - 1]; + auto q = organelle.q; + auto r = organelle.r; + // TODO: this could be done more efficiently + MicrobeOperations::removeOrganelle(world, microbeEntity, {q, r}); + } + + // give it organelles + for(uint i = 0; i < species.organelles.length(); ++i){ + + PlacedOrganelle@ organelle = PlacedOrganelle( + cast(species.organelles[i])); + + MicrobeOperations::addOrganelle(world, microbeEntity, organelle); + } +} + +//! Creates a species from the initial template. This doesn't register with SpeciesSystem +//! because this is (currently) only used for the player's species which isn't managed by it +ObjectID createSpecies(CellStageWorld@ world, const string &in name, + MicrobeTemplate@ fromTemplate +) { + array convertedOrganelles; + for(uint i = 0; i < fromTemplate.organelles.length(); ++i){ + + OrganelleTemplatePlaced@ organelle = fromTemplate.organelles[i]; + + convertedOrganelles.insertLast(PlacedOrganelle( + getOrganelleDefinition(organelle.type), organelle.q, organelle.r, + organelle.rotation)); + } + + return createSpecies(world, name, convertedOrganelles, fromTemplate.colour, false, + fromTemplate.compounds); +} + +//! Creates an entity that has all the species stuff on it +//! AI controlled ones need to be in addition in SpeciesSystem +ObjectID createSpecies(CellStageWorld@ world, const string &in name, + array organelles, Float4 colour, bool isBacteria, const dictionary &in compounds +) { + ObjectID speciesEntity = world.CreateEntity(); + + SpeciesComponent@ speciesComponent = world.Create_SpeciesComponent(speciesEntity, + name); + + @speciesComponent.avgCompoundAmounts = dictionary(); + + @speciesComponent.organelles = array(); + for(uint i = 0; i < organelles.length(); ++i){ + + // This conversion does a little bit of extra calculations (that are in the + // end not used) + speciesComponent.organelles.insertLast(PlacedOrganelle(organelles[i])); + } + + // Verify it // + for(uint i = 0; i < speciesComponent.organelles.length(); ++i){ + + PlacedOrganelle@ organelle = cast(speciesComponent.organelles[i]); + + if(organelle is null){ + + assert(false, "createSpecies: species.organelles has invalid object at index: " + + i); + } + } + + ProcessorComponent@ processorComponent = world.Create_ProcessorComponent( + speciesEntity); + + speciesComponent.colour = colour; + //we need to know this is baceria + speciesComponent.isBacteria = isBacteria; + // iterates over all compounds, and sets amounts and priorities + uint64 compoundCount = SimulationParameters::compoundRegistry().getSize(); + for(uint i = 0; i < compoundCount; ++i){ + + auto compound = SimulationParameters::compoundRegistry().getTypeData(i); + + if(!compounds.exists(compound.internalName)) + continue; + + InitialCompound compoundAmount; + if(!compounds.get(compound.internalName, compoundAmount)){ + + assert(false, "createSpecies: invalid data in compounds, with key: " + + compound.internalName); + continue; + } + + speciesComponent.avgCompoundAmounts[formatUInt(compound.id)] = compoundAmount; + } + + dictionary capacities; + for(uint i = 0; i < organelles.length(); ++i){ + + const Organelle@ organelleDefinition = organelles[i].organelle; + if(organelleDefinition is null){ + + LOG_ERROR("Organelle table has a null organelle in it, position: " + i + + "', that was added to a species entity"); + continue; + } + + for(uint processNumber = 0; + processNumber < organelleDefinition.processes.length(); ++processNumber) + { + // This name needs to match the one in bioProcessRegistry + TweakedProcess@ process = organelleDefinition.processes[processNumber]; + + if(!capacities.exists(process.process.internalName)){ + capacities[process.process.internalName] = 0; + } + + // Here the second capacities[process.name] was initially capacities[process] + // but the processes are just strings inside the Organelle class + capacities[process.process.internalName] = float(capacities[ + process.process.internalName]) + + process.capacity; + } + } + + uint64 processCount = SimulationParameters::bioProcessRegistry().getSize(); + for(uint bioProcessId = 0; bioProcessId < processCount; ++bioProcessId){ + + auto processName = SimulationParameters::bioProcessRegistry().getInternalName( + bioProcessId); + + if(capacities.exists(processName)){ + + float capacity; + if(!capacities.get(processName, capacity)){ + LOG_ERROR("capacities has invalid value"); + continue; + } + + processorComponent.setCapacity(bioProcessId, capacity); + // This may be commented out for the reason that the default should be retained + // } else { + // processorComponent.setCapacity(bioProcessId, 0) + } + } + + return speciesEntity; +} + + +//! Mutates a species' dna code randomly +string mutate(const string &in stringCode){ + //moving the stringCode to a table to facilitate changes + string chromosomes = stringCode.substr(2); + + //try to insert a letter at the end of the table. + if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_CREATION_RATE){ + chromosomes += getRandomLetter(); + } + + //modifies the rest of the table. + for(uint i = 0; i < stringCode.length(); ++i){ + uint index = stringCode.length() - i; + + if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_DELETION_RATE){ + chromosomes.erase(index, 1); + } + + if(GetEngine().GetRandom().GetNumber(0.f, 1.f) < MUTATION_CREATION_RATE){ + chromosomes.insert(index, getRandomLetter()); + } + } + + //transforming the table back into a string + // TODO: remove Hardcoded microbe genes + auto newString = "NY" + chromosomes; + return newString; +} + + +//! Calls resetAutoEvo on world's SpeciesSystem +void resetAutoEvo(CellStageWorld@ world){ + cast(world.GetScriptSystem("SpeciesSystem")).resetAutoEvo(); +} + +} + diff --git a/scripts/microbe_stage/species_system.lua b/scripts/microbe_stage/species_system.lua deleted file mode 100644 index da6d411a798..00000000000 --- a/scripts/microbe_stage/species_system.lua +++ /dev/null @@ -1,440 +0,0 @@ --------------------------------------------------------------------------------- --- Species class --- --- Class for representing an individual species --------------------------------------------------------------------------------- ---limits the size of the initial stringCodes -local MIN_INITIAL_LENGTH = 5 -local MAX_INITIAL_LENGTH = 15 - -local DEFAULT_SPAWN_DENSITY = 1/25000 - -local MIN_COLOR = 0.3 -local MAX_COLOR = 1.0 - -local MUTATION_CREATION_RATE = 0.1 -local MUTATION_DELETION_RATE = 0.1 - --- Why is the latest created species system accessible globally here? --- this will cause problems in the future -local gSpeciesSystem = nil - -local function randomColour() - return math.random() * (MAX_COLOR - MIN_COLOR) + MIN_COLOR -end - -local DEFAULT_INITIAL_COMPOUNDS = - { - atp = {priority=10,amount=60}, - glucose = {amount = 10}, - reproductase = {priority = 8}, - oxygen = {amount = 10}, - oxytoxy = {amount = 1} - } - -Species = class( - function(self) - - self.population = INITIAL_POPULATION - self.name = "Species_" .. tostring(math.random()) --gotta use the latin names - - local stringSize = math.random(MIN_INITIAL_LENGTH, MAX_INITIAL_LENGTH) - self.stringCode = organelleTable.nucleus.gene .. organelleTable.cytoplasm.gene --it should always have a nucleus and a cytoplasm. - for i = 1, stringSize do - self.stringCode = self.stringCode .. getRandomLetter() - end - - local organelles = positionOrganelles(self.stringCode) - - self.colour = { - r = randomColour(), - g = randomColour(), - b = randomColour() - } - - self.template = createSpeciesTemplate(self.name, organelles, self.colour, DEFAULT_INITIAL_COMPOUNDS, nil) - self:setupSpawn() - - end -) - ---sets up the spawn of the species -function Species:setupSpawn() - self.id = gSpawnSystem:addSpawnType( - function(pos) - return microbeSpawnFunctionGeneric(pos, self.name, true, nil, - g_luaEngine.currentGameState) - end, - DEFAULT_SPAWN_DENSITY, --spawnDensity should depend on population - MICROBE_SPAWN_RADIUS - ) -end - ---copy-pasted from setupSpecies in setup.lua -function createSpeciesTemplate(name, organelles, colour, compounds, speciesThresholds) - speciesEntity = Entity.new(name, g_luaEngine.currentGameState.wrapper) - speciesComponent = SpeciesComponent.new(name) - speciesEntity:addComponent(speciesComponent) - for i, organelle in pairs(organelles) do - local org = {} - org.name = organelle.name - org.q = organelle.q - org.r = organelle.r - org.rotation = organelle.rotation - speciesComponent.organelles[i] = org - end - processorComponent = ProcessorComponent.new() - speciesEntity:addComponent(processorComponent) - speciesComponent.colour = Vector3(colour.r, colour.g, colour.b) - -- iterates over all compounds, and sets amounts and priorities - for _, compoundID in pairs(CompoundRegistry.getCompoundList()) do - compound = CompoundRegistry.getCompoundInternalName(compoundID) - - compoundData = compounds[compound] - if compoundData ~= nil then - amount = compoundData.amount - -- priority = compoundData.priority - speciesComponent.avgCompoundAmounts["" .. compoundID] = amount - -- speciesComponent.compoundPriorities[compoundID] = priority - end - end - - local capacities = {} - for _, organelle in pairs(organelles) do - if organelleTable[organelle.name] ~= nil then - if organelleTable[organelle.name]["processes"] ~= nil then - for process, capacity in pairs(organelleTable[organelle.name]["processes"]) do - if capacities[process] == nil then - capacities[process] = 0 - end - capacities[process] = capacities[process] + capacity - end - end - end - end - for _, bioProcessId in pairs(BioProcessRegistry.getList()) do - local name = BioProcessRegistry.getInternalName(bioProcessId) - if capacities[name] ~= nil then - processorComponent:setCapacity(bioProcessId, capacities[name]) - -- else - -- processorComponent:setCapacity(bioProcessId, 0) - end - end - return speciesEntity -end - ---updates the population count of the species -function Species:updatePopulation() - --TODO: - --fill me - --with code - self.population = self.population + math.random(-200, 200) -end - ---delete a species -function Species:extinguish() - currentSpawnSystem:removeSpawnType(self.id) - --self.template:destroy() --game crashes if i do that. -end - -local function mutate(stringCode) - --moving the stringCode to a table to facilitate changes - local chromosomes = {} - local originalStringSize = 0 - for i = 3, string.len(stringCode) do - table.insert(chromosomes, string.sub(stringCode, i, i)) - originalStringSize = originalStringSize + 1 - end - - --try to insert a letter at the end of the table. - if math.random() < MUTATION_CREATION_RATE then - table.insert(chromosomes, getRandomLetter()) - end - - --modifies the rest of the table. - for i = 0, originalStringSize - 1 do - index = originalStringSize - i - - if math.random() < MUTATION_DELETION_RATE then - table.remove(chromosomes, index) - end - - if math.random() < MUTATION_CREATION_RATE then - table.insert(chromosomes, index, getRandomLetter()) - end - end - - --transforming the table back into a string - local newString = "NY" - for _, letter in pairs(chromosomes) do - newString = newString .. letter - end - - return newString -end - ---returns a mutated version of the species and reduces the species population by half -function Species:getChild(parent, r, g, b) - self.name = "Species_" .. tostring(math.random()) - self.colour = {} - self.colour.r = (r + randomColour()) / 2 - self.colour.g = (g + randomColour()) / 2 - self.colour.b = (b + randomColour()) / 2 - self.population = math.floor(parent.population / 2) - self.stringCode = mutate(parent.stringCode) - - local organelles = positionOrganelles(parent.stringCode) - - self.template = createSpeciesTemplate(self.name, organelles, self.colour, DEFAULT_INITIAL_COMPOUNDS, nil) - self:setupSpawn() - - parent.population = math.ceil(parent.population / 2) - return self -end --------------------------------------------------------------------------------- --- SpeciesSystem --- --- System for estimating and simulating population count for various species --------------------------------------------------------------------------------- - ---How big is a newly created species's population. -INITIAL_POPULATION = 2000 - ---how much time does it take for the simulation to update. -SPECIES_SIM_INTERVAL = 20000 - ---if a specie's population goes below this it goes extinct. -MIN_POP_SIZE = 100 - ---if a specie's population goes above this it gets split in half and a new mutated specie apears. -MAX_POP_SIZE = 5000 - ---the amount of species at the start of the microbe stage (not counting Default/Player) -INITIAL_SPECIES = 7 - ---if there are more species than this then all species get their population reduced by half -MAX_SPECIES = 15 - ---if there are less species than this create new ones. -MIN_SPECIES = 3 - - -SpeciesSystem = class( - LuaSystem, - function(self) - - LuaSystem.create(self) - - self.entities = EntityFilter.new( - { - SpeciesComponent, - ProcessorComponent, - }, - true - ) - self.timeSinceLastCycle = 0 - - end -) - -function resetAutoEvo() - if gSpeciesSystem.species ~= nil then - for _, species in pairs(gSpeciesSystem.species) do - species:extinguish() - end - - gSpeciesSystem.species = {} - gSpeciesSystem.number_of_species = 0 - end -end - --- Override from System -function SpeciesSystem:init(gameState) - LuaSystem.init(self, "SpeciesSystem", gameState) - self.entities:init(gameState.wrapper) - - self.species = {} - self.number_of_species = 0 - - --doing this crashes the game - --probably because init gets called twice - --running this in only one of those calls crashes the game - --(somehow) - - --for i = 1, INITIAL_SPECIES do - -- newSpecies = Species:init() - -- table.insert(self.species, newSpecies) - -- self.number_of_species = self.number_of_species + 1 - --end - gSpeciesSystem = self -end - --- Override from System -function SpeciesSystem:shutdown() - self.entities:shutdown() - LuaSystem.shutdown(self) -end - --- Override from System -function SpeciesSystem:activate() - --[[ - This runs in two (three?) use-cases: - - First, it runs on game entry from main menu -- in this case, it must set up for new game - - Second, it runs on game entry from editor -- in this case, it can set up the new species - (in conjunction with stuff in editor, called on finish-click) - - Third (possibly) it might run on load. - --]] -end - -function SpeciesSystem:doMassExtinction() - for _, currentSpecies in pairs(self.species) do - currentSpecies.population = math.floor(currentSpecies.population / 2) - end -end - --- Override from System -function SpeciesSystem:update(_, milliseconds) - gSpeciesSystem = self --so hacky :c - self.timeSinceLastCycle = self.timeSinceLastCycle + milliseconds - while self.timeSinceLastCycle > SPECIES_SIM_INTERVAL do - --update population numbers and split/extinct species as needed - local numberOfSpecies = self.number_of_species - for i = 0, numberOfSpecies - 1 do - local index = numberOfSpecies - i --traversing the population backwards to avoid - --"chopping down the branch i'm sitting in" - - currentSpecies = self.species[index] - currentSpecies:updatePopulation() - local population = currentSpecies.population - - --reproduction/mutation - if population > MAX_POP_SIZE then - local newSpecies = Species:getChild(currentSpecies, - currentSpecies.colour.r, - currentSpecies.colour.g, - currentSpecies.colour.b) - table.insert(self.species, newSpecies) - self.number_of_species = self.number_of_species + 1 - end - - --extinction - if population < MIN_POP_SIZE then - currentSpecies:extinguish() - table.remove(self.species, index) - self.number_of_species = self.number_of_species - 1 - end - end - - --new species - if self.number_of_species < MIN_SPECIES then - for i = self.number_of_species, INITIAL_SPECIES - 1 do - newSpecies = Species() - table.insert(self.species, newSpecies) - self.number_of_species = self.number_of_species + 1 - end - end - - --mass extinction - if self.number_of_species > MAX_SPECIES then - self:doMassExtinction() - end - - self.timeSinceLastCycle = self.timeSinceLastCycle - SPECIES_SIM_INTERVAL - end -end - -function SpeciesSystem.initProcessorComponent(entity, speciesComponent) - local sc = getComponent(entity, SpeciesComponent) - if sc == nil then - entity:addComponent(speciesComponent) - end - - local pc = getComponent(entity, ProcessorComponent) - if pc == nil then - pc = ProcessorComponent.new() - entity:addComponent(pc) - end - - local capacities = {} - for _, organelle in pairs(speciesComponent.organelles) do - if organelleTable[organelle.name] ~= nil then - if organelleTable[organelle.name]["processes"] ~= nil then - for process, capacity in pairs(organelleTable[organelle.name]["processes"]) do - if capacities[process] == nil then - capacities[process] = 0 - end - capacities[process] = capacities[process] + capacity - end - end - end - end - for _, bioProcessID in pairs(BioProcessRegistry.getList()) do - local name = BioProcessRegistry.getInternalName(bioProcessID) - if capacities[name] ~= nil then - pc:setCapacity(bioProcessID, capacities[name]) - end - end -end - --- Given a newly-created microbe, this sets the organelles and all other species-specific microbe data --- like agent codes, for example. -function SpeciesSystem.template(microbeEntity, species) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - - -- TODO: Make this also set the microbe's ProcessorComponent - microbeComponent.speciesName = species.name - MicrobeSystem.setMembraneColour(microbeEntity, species.colour) - - SpeciesSystem.restoreOrganelleLayout(microbeEntity, species) - - for compoundID, amount in pairs(species.avgCompoundAmounts) do - if amount ~= 0 then - MicrobeSystem.storeCompound(microbeEntity, compoundID, amount, false) - end - end - - return microbeEntity -end - -function SpeciesSystem.restoreOrganelleLayout(microbeEntity, species) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - - -- delete the the previous organelles. - for s, organelle in pairs(microbeComponent.organelles) do - local q = organelle.position.q - local r = organelle.position.r - MicrobeSystem.removeOrganelle(microbeEntity, q, r) - end - - -- give it organelles - microbeComponent.organelles = {} - for _, orgdata in pairs(species.organelles) do - organelle = OrganelleFactory.makeOrganelle(orgdata) - MicrobeSystem.addOrganelle(microbeEntity, orgdata.q, orgdata.r, orgdata.rotation, organelle) - end -end - -function SpeciesSystem.fromMicrobe(microbeEntity, species) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - local membraneComponent = getComponent(microbeEntity, MembraneComponent) - - -- self.name = microbeComponent.speciesName - species.colour = membraneComponent:getColour() - - -- Create species' organelle data - for i, organelle in pairs(microbeComponent.organelles) do - local data = {} - data.name = organelle.name - data.q = organelle.position.q - data.r = organelle.position.r - data.rotation = organelle.rotation - species.organelles[i] = data - end - -- This microbes compound amounts will be the new population average. - species.avgCompoundAmounts = {} - for _, compoundID in pairs(CompoundRegistry.getCompoundList()) do - local amount = MicrobeSystem.getCompoundAmount(microbeEntity, compoundID) - species.avgCompoundAmounts["" .. compoundID] = amount - end - -- TODO: make this update the ProcessorComponent based on microbe thresholds -end diff --git a/scripts/microbe_stage/storage_organelle.as b/scripts/microbe_stage/storage_organelle.as new file mode 100644 index 00000000000..6543de17a96 --- /dev/null +++ b/scripts/microbe_stage/storage_organelle.as @@ -0,0 +1,54 @@ +#include "organelle_component.as" +#include "microbe_operations.as" + +//////////////////////////////////////////////////////////////////////////////// +// A storage organelle class +//////////////////////////////////////////////////////////////////////////////// +class StorageOrganelle : OrganelleComponent{ + + StorageOrganelle(float capacity){ + + this.capacity = capacity; + } + + // See organelle_component.lua for more information about the + // organelle component methods and the arguments they receive. + + // void StorageOrganelle.load(storage){ + // this.capacity = storage.get("capacity", 100) + // } + + // void StorageOrganelle.storage(){ + // auto storage = StorageContainer() + // storage.set("capacity", this.capacity) + // return storage + // } + + // Overridded from Organelle.onAddedToMicrobe + void + onAddedToMicrobe( + ObjectID microbeEntity, + int q, int r, int rotation, + PlacedOrganelle@ organelle + ) override { + + MicrobeComponent@ microbeComponent = cast( + organelle.world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + microbeComponent.capacity += this.capacity; + } + + // Overridded from Organelle.onRemovedFromMicrobe + void + onRemovedFromMicrobe( + ObjectID microbeEntity, + PlacedOrganelle@ organelle + ) override { + MicrobeComponent@ microbeComponent = cast( + organelle.world.GetScriptComponentHolder("MicrobeComponent").Find(microbeEntity)); + + microbeComponent.capacity -= this.capacity; + } + + private float capacity; +} diff --git a/scripts/microbe_stage/storage_organelle.lua b/scripts/microbe_stage/storage_organelle.lua deleted file mode 100644 index fcb6fa2474f..00000000000 --- a/scripts/microbe_stage/storage_organelle.lua +++ /dev/null @@ -1,47 +0,0 @@ --------------------------------------------------------------------------------- --- A storage organelle class --------------------------------------------------------------------------------- -StorageOrganelle = class( - OrganelleComponent, - -- Constructor - -- - -- @param arguments.capacity - -- The maximum stored amount - function(self, arguments, data) - OrganelleComponent.create(self, arguments, data) - - --making sure this doesn't run when load() is called - if arguments == nil and data == nil then - return - end - - self.capacity = arguments.capacity - return self - end -) - --- See organelle_component.lua for more information about the --- organelle component methods and the arguments they receive. - -function StorageOrganelle:load(storage) - self.capacity = storage:get("capacity", 100) -end - -function StorageOrganelle:storage() - local storage = StorageContainer.new() - storage:set("capacity", self.capacity) - return storage -end - --- Overridded from Organelle:onAddedToMicrobe -function StorageOrganelle:onAddedToMicrobe(microbeEntity, q, r, rotation, organelle) - OrganelleComponent.onAddedToMicrobe(self, microbe, q, r, rotation, organelle) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - microbeComponent.capacity = microbeComponent.capacity + self.capacity -end - --- Overridded from Organelle:onRemovedFromMicrobe -function StorageOrganelle:onRemovedFromMicrobe(microbeEntity, q, r) - local microbeComponent = getComponent(microbeEntity, MicrobeComponent) - microbeComponent.capacity = microbeComponent.capacity - self.capacity -end diff --git a/scripts/microbe_stage_tutorial/microbe_stage_tutorial_hud.lua b/scripts/microbe_stage/tutorial/microbe_stage_tutorial_hud.lua similarity index 100% rename from scripts/microbe_stage_tutorial/microbe_stage_tutorial_hud.lua rename to scripts/microbe_stage/tutorial/microbe_stage_tutorial_hud.lua diff --git a/scripts/microbe_stage_tutorial/manifest.txt b/scripts/microbe_stage_tutorial/manifest.txt deleted file mode 100644 index 7215ad49441..00000000000 --- a/scripts/microbe_stage_tutorial/manifest.txt +++ /dev/null @@ -1,4 +0,0 @@ - -// Setup -microbe_stage_tutorial_hud.lua -setup.lua diff --git a/scripts/microbe_stage_tutorial/setup.lua b/scripts/microbe_stage_tutorial/setup.lua deleted file mode 100644 index 078cc0e6770..00000000000 --- a/scripts/microbe_stage_tutorial/setup.lua +++ /dev/null @@ -1,164 +0,0 @@ ---The biome in which the tutorial is played. -TUTORIAL_BIOME = "default" - -local function setupBackground(gameState) - --Actually changing the biome makes the biome after the tutorial be default - --but with a different background. - local entity = Entity.new("background", gameState.wrapper) - local skyplane = SkyPlaneComponent.new() - skyplane.properties.plane.normal = Vector3(0, 0, 2000) - skyplane.properties.materialName = biomeTable[TUTORIAL_BIOME].background - skyplane.properties.scale = 200 - skyplane.properties:touch() - entity:addComponent(skyplane) -end - -local function setupCamera(gameState) - local entity = Entity.new(CAMERA_NAME, gameState.wrapper) - -- Camera - local camera = OgreCameraComponent.new("camera") - camera.properties.nearClipDistance = 5 - camera.properties.offset = Vector3(0, 0, 30) - camera.properties:touch() - entity:addComponent(camera) - -- Scene node - local sceneNode = OgreSceneNodeComponent.new() - sceneNode.transform.position.z = 30 - sceneNode.transform:touch() - entity:addComponent(sceneNode) - -- Light - local light = OgreLightComponent.new() - light:setRange(200) - entity:addComponent(light) - -- Workspace - local workspaceEntity = Entity.new(gameState.wrapper) - local workspaceComponent = OgreWorkspaceComponent.new("thrive_default") - workspaceComponent.properties.cameraEntity = entity - workspaceComponent.properties.position = 0 - workspaceComponent.properties:touch() - workspaceEntity:addComponent(workspaceComponent) -end - -local function setupCompoundClouds(gameState) - for compoundName, compoundInfo in pairs(compoundTable) do - if compoundInfo.isCloud then - local compoundId = CompoundRegistry.getCompoundId(compoundName) - local entity = Entity.new("compound_cloud_" .. compoundName, gameState.wrapper) - local compoundCloud = CompoundCloudComponent.new() - local colour = compoundInfo.colour - compoundCloud:initialize(compoundId, colour.r, colour.g, colour.b) - entity:addComponent(compoundCloud) - end - end -end - -local function setupPlayer(gameState) - local entity = Entity.new(PLAYER_NAME, gameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - entity:addComponent(sceneNode) - Engine:playerData():setActiveCreature(entity.id, GameState.MICROBE_TUTORIAL.wrapper) - -- local microbe = Microbe.createMicrobeEntity(PLAYER_NAME, false) - -- getComponent(Entity("Default"), SpeciesComponent):template(microbe) - -- microbe.collisionHandler:addCollisionGroup("powerupable") - -- Engine:playerData():lockedMap():addLock("Toxin") - -- Engine:playerData():lockedMap():addLock("chloroplast") - -- Engine:playerData():setActiveCreature(microbe.entity.id, GameState.MICROBE_TUTORIAL) - -- speciesEntity = Entity("defaultMicrobeSpecies") - -- species = SpeciesComponent("Default") - -- species:fromMicrobe(microbe) - -- speciesEntity:addComponent(species) - -- microbe.microbe.speciesName = "Default" -end - - -local function setupSound(gameState) - local ambientEntity = Entity.new("ambience", gameState.wrapper) - local soundSource = SoundSourceComponent.new() - soundSource.ambientSoundSource = true - soundSource.autoLoop = true - soundSource.volumeMultiplier = 0.5 - ambientEntity:addComponent(soundSource) - -- Sound - soundSource:addSound("microbe-theme-1", "microbe-theme-1.ogg") - soundSource:addSound("microbe-theme-3", "microbe-theme-3.ogg") - soundSource:addSound("microbe-theme-4", "microbe-theme-4.ogg") - soundSource:addSound("microbe-theme-5", "microbe-theme-5.ogg") - soundSource:addSound("microbe-theme-6", "microbe-theme-6.ogg") - soundSource:addSound("microbe-theme-7", "microbe-theme-7.ogg") - local ambientEntity2 = Entity.new("ambience2", gameState.wrapper) - local soundSource = SoundSourceComponent.new() - soundSource.volumeMultiplier = 0.3 - soundSource.ambientSoundSource = true - ambientSound = soundSource:addSound("microbe-ambient", "soundeffects/microbe-ambience.ogg") - soundSource.autoLoop = true - ambientEntity2:addComponent(soundSource) - -- Gui effects - local guiSoundEntity = Entity.new("gui_sounds", gameState.wrapper) - soundSource = SoundSourceComponent.new() - soundSource.ambientSoundSource = true - soundSource.autoLoop = false - soundSource.volumeMultiplier = 1.0 - guiSoundEntity:addComponent(soundSource) - -- Sound - soundSource:addSound("button-hover-click", "soundeffects/gui/button-hover-click.ogg") - soundSource:addSound("microbe-pickup-organelle", "soundeffects/microbe-pickup-organelle.ogg") - local listener = Entity.new("soundListener", gameState.wrapper) - local sceneNode = OgreSceneNodeComponent.new() - listener:addComponent(sceneNode) -end - -local function createMicrobeStageTutorial(name) - return - g_luaEngine:createGameState( - name, - { - QuickSaveSystem.new(), - -- Microbe specific - MicrobeSystem.new(), - MicrobeCameraSystem.new(), - MicrobeAISystem.new(), - MicrobeControlSystem.new(), - MicrobeStageTutorialHudSystem.new(), - TimedLifeSystem.new(), - CompoundMovementSystem.new(), - CompoundAbsorberSystem.new(), - --PopulationSystem.new(), - PatchSystem.new(), - SpeciesSystem.new(), - -- Physics - RigidBodyInputSystem.new(), - UpdatePhysicsSystem.new(), - RigidBodyOutputSystem.new(), - BulletToOgreSystem.new(), - CollisionSystem.new(), - -- Graphics - OgreAddSceneNodeSystem.new(), - OgreUpdateSceneNodeSystem.new(), - OgreCameraSystem.new(), - OgreLightSystem.new(), - SkySystem.new(), - OgreWorkspaceSystem.new(), - OgreRemoveSceneNodeSystem.new(), - RenderSystem.new(), - MembraneSystem.new(), - CompoundCloudSystem.new(), - -- Other - SoundSourceSystem.new(), - PowerupSystem.new(), - CompoundEmitterSystem.new(), -- Keep this after any logic that might eject compounds such that any entites that are queued for destruction will be destroyed after emitting. - }, - true, - "MicrobeStageTutorial", - function(gameState) - setupBackground(gameState) - setupCamera(gameState) - setupCompoundClouds(gameState) - setupSpecies(gameState) - setupPlayer(gameState) - setupSound(gameState) - end - ) -end - -GameState.MICROBE_TUTORIAL = createMicrobeStageTutorial("microbe_tutorial") ---Engine:setCurrentGameState(GameState.MICROBE_TUTORIAL) diff --git a/scripts/script_system.as b/scripts/script_system.as new file mode 100644 index 00000000000..68c08d0632a --- /dev/null +++ b/scripts/script_system.as @@ -0,0 +1,4 @@ +// Common functions for systems defined in scripts + + + diff --git a/scripts/win-update-scripts-and-run.bat b/scripts/win-update-scripts-and-run.bat deleted file mode 100644 index e86143673a6..00000000000 --- a/scripts/win-update-scripts-and-run.bat +++ /dev/null @@ -1,6 +0,0 @@ -xcopy /e /v /Y . .\..\build\dist\scripts\ - -cd .\..\build\dist\bin\ -Thrive.exe - -timeout /t -1 \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 83042d9eefa..dfb498246f5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,14 +1,207 @@ -add_sources( - "${CMAKE_CURRENT_SOURCE_DIR}/game.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/game.h" -) - -add_subdirectory(bullet) -add_subdirectory(engine) -add_subdirectory(general) -add_subdirectory(gui) -add_subdirectory(microbe_stage) -add_subdirectory(ogre) -add_subdirectory(scripting) -add_subdirectory(sound) -add_subdirectory(util) + + +# Add source files to the list +set(GROUP_ENGINE + "engine/typedefs.h" + "engine/player_data.cpp" + "engine/player_data.h" + # "engine/rolling_grid.cpp" + # "engine/rolling_grid.h" + "engine/serialization.cpp" + "engine/serialization.h" + ) + +set(GROUP_GENERAL + "general/timed_life_system.cpp" + "general/timed_life_system.h" + "general/locked_map.cpp" + "general/locked_map.h" + "general/hex.cpp" + "general/hex.h" + # "general/powerup_system.cpp" + # "general/powerup_system.h" + "general/perlin_noise.cpp" + "general/perlin_noise.h" + "general/thrive_math.cpp" + "general/thrive_math.h" + ) + +set(GROUP_MICROBE_STAGE + "microbe_stage/agent_cloud_system.cpp" + "microbe_stage/agent_cloud_system.h" + "microbe_stage/bacteria_types.cpp" + "microbe_stage/bacteria_types.h" + "microbe_stage/biome_controller.cpp" + "microbe_stage/biome_controller.h" + "microbe_stage/biomes.cpp" + "microbe_stage/biomes.h" + "microbe_stage/bioprocesses.cpp" + "microbe_stage/bioprocesses.h" + "microbe_stage/compound_absorber_system.cpp" + "microbe_stage/compound_absorber_system.h" + "microbe_stage/compound_cloud_system.cpp" + "microbe_stage/compound_cloud_system.h" + "microbe_stage/compounds.cpp" + "microbe_stage/compounds.h" + "microbe_stage/generate_cell_stage_world.rb" + "microbe_stage/generate_microbe_editor_world.rb" + "microbe_stage/membrane_system.cpp" + "microbe_stage/membrane_system.h" + "microbe_stage/microbe_camera_system.cpp" + "microbe_stage/microbe_camera_system.h" + "microbe_stage/organelle_types.cpp" + "microbe_stage/organelle_types.h" + "microbe_stage/process_system.cpp" + "microbe_stage/process_system.h" + "microbe_stage/simulation_parameters.cpp" + "microbe_stage/simulation_parameters.h" + "microbe_stage/spawn_system.cpp" + "microbe_stage/spawn_system.h" + "microbe_stage/species.cpp" + "microbe_stage/species.h" + "microbe_stage/species_component.cpp" + "microbe_stage/species_component.h" + "microbe_stage/species_name_controller.cpp" + "microbe_stage/species_name_controller.h" + "microbe_stage/player_microbe_control.h" + "microbe_stage/player_microbe_control.cpp" + ) + +set_source_files_properties("microbe_stage/generate_cell_stage_world.rb" + PROPERTIES HEADER_FILE_ONLY TRUE) + +set_source_files_properties("microbe_stage/generate_microbe_editor_world.rb" + PROPERTIES HEADER_FILE_ONLY TRUE) + +set(GROUP_SCRIPTING + # "scripting/script_initializer.cpp" + # "scripting/script_initializer.h" + ) + +set(GROUP_UTIL + "util/pair_hash.h" + ) + + +add_custom_command(OUTPUT "${PROJECT_SOURCE_DIR}/src/generated/cell_stage_world.h" + "${PROJECT_SOURCE_DIR}/src/generated/cell_stage_world.cpp" + "${PROJECT_SOURCE_DIR}/src/generated/cell_stage_bindings.h" + COMMAND "ruby" "${PROJECT_SOURCE_DIR}/src/microbe_stage/generate_cell_stage_world.rb" + "${PROJECT_SOURCE_DIR}/src/generated/cell_stage_world" + "${PROJECT_SOURCE_DIR}/src/generated/cell_stage_bindings.h" + DEPENDS "${PROJECT_SOURCE_DIR}/src/microbe_stage/generate_cell_stage_world.rb" + "${LEVIATHAN_SRC}/Helpers/FileGen.rb" + ) + +add_custom_command(OUTPUT "${PROJECT_SOURCE_DIR}/src/generated/microbe_editor_world.h" + "${PROJECT_SOURCE_DIR}/src/generated/microbe_editor_world.cpp" + "${PROJECT_SOURCE_DIR}/src/generated/microbe_editor_bindings.h" + COMMAND "ruby" "${PROJECT_SOURCE_DIR}/src/microbe_stage/generate_microbe_editor_world.rb" + "${PROJECT_SOURCE_DIR}/src/generated/microbe_editor_world" + "${PROJECT_SOURCE_DIR}/src/generated/microbe_editor_bindings.h" + DEPENDS "${PROJECT_SOURCE_DIR}/src/microbe_stage/generate_microbe_editor_world.rb" + "${LEVIATHAN_SRC}/Helpers/FileGen.rb" + ) + +set(GROUP_MICROBE + "generated/cell_stage_world.h" "generated/cell_stage_world.cpp" + "generated/cell_stage_bindings.h" + "generated/microbe_editor_world.h" "generated/microbe_editor_world.cpp" + "generated/microbe_editor_bindings.h" + ) + +# Menu things +set(GROUP_MENU + "main_menu_keypresses.cpp" + "main_menu_keypresses.h" + ) + + +# Groups for better visual studio experience +source_group("bullet" FILES ${GROUP_BULLET}) +source_group("engine" FILES ${GROUP_ENGINE}) +source_group("general" FILES ${GROUP_GENERAL}) +source_group("gui" FILES ${GROUP_GUI}) +source_group("microbe_stage" FILES ${GROUP_MICROBE_STAGE}) +source_group("ogre" FILES ${GROUP_OGRE}) +source_group("scripting" FILES ${GROUP_SCRIPTING}) +source_group("sound" FILES ${GROUP_SOUND}) +source_group("util" FILES ${GROUP_UTIL}) + +source_group("menu_code" FILES ${GROUP_MENU}) + +source_group("microbe" FILES ${GROUP_MICROBE}) + + + +set(THRIVE_FILES ${GROUP_BULLET} ${GROUP_ENGINE} + ${GROUP_GENERAL} ${GROUP_GUI} ${GROUP_MICROBE_STAGE} + ${GROUP_OGRE} ${GROUP_SCRIPTING} ${GROUP_SOUND} + ${GROUP_UTIL} ${GROUP_MICROBE} + ${GROUP_MENU} + ) + +# Leviathan program setup + +set(BaseProgramName "Thrive") +set(BaseIncludeFileName "thrive_version.h") +set(BaseSubFolder "src") + +# Set all the settings +set(ProgramIncludesHeader "${BaseIncludeFileName}") +set(ProgramAppHeader "ThriveGame.h") + +set(WorldFactoryClass "ThriveWorldFactory") +set(WorldFactoryInclude "thrive_world_factory.h") + + +# ------------------ ProgramConfiguration ------------------ # +set(PROGRAMCLASSNAME ThriveGame) +set(PROGRAMLOG Thrive) +set(PROGRAMCONFIGURATION "./ThriveGame.conf") +set(PROGRAMKEYCONFIGURATION "./ThriveKeybindings.conf") +set(PROGRAMCHECKCONFIGFUNCNAME "ThriveGame::CheckGameConfigurationVariables") +set(PROGRAMCHECKKEYCONFIGFUNCNAME "ThriveGame::CheckGameKeyConfigVariables") +set(WINDOWTITLEGENFUNCTION "ThriveGame::GenerateWindowTitle()") +set(USERREADABLEIDENTIFICATION "\"Thrive game version \" GAME_VERSIONS") + +set(PROGRAMUSE_CUSTOMJS 0) + +# Configure main and thrive_version.h files +StandardConfigureExecutableMainAndInclude("${BaseIncludeFileName}" "main.cpp" + "${BaseSubFolder}" "${PROJECT_SOURCE_DIR}/${BaseSubFolder}") + + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +set(CurrentProjectName Thrive) +set(AllProjectFiles + ${BaseIncludeFileName} + "main.cpp" + "ThriveGame.h" "ThriveGame.cpp" + "thrive_world_factory.h" "thrive_world_factory.cpp" + "thrive_net_handler.h" "thrive_net_handler.cpp" + ) + +# Compile a common library +add_library(ThriveLib STATIC ${THRIVE_FILES}) + +set_target_properties(ThriveLib PROPERTIES + OUTPUT_NAME Thrive + ) + +set_property(TARGET ThriveLib PROPERTY CXX_STANDARD 17) +set_property(TARGET ThriveLib PROPERTY CXX_EXTENSIONS OFF) + +target_compile_definitions(ThriveLib PRIVATE "THRIVELIB_BUILD=1") + +target_link_libraries(ThriveLib ${DEPENDENT_LIBS}) + +# Include the common file +set(CREATE_CONSOLE_APP OFF) +include(LeviathanUsingProject) + +# The project is now defined +target_link_libraries(Thrive ThriveLib) + + diff --git a/src/Main.cpp b/src/Main.cpp deleted file mode 100644 index 349bc850262..00000000000 --- a/src/Main.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include "game.h" -#include -#include -#include - -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 -#define WIN32_LEAN_AND_MEAN -#include "windows.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * - * Init function. Anything that has to happen first goes here - * - * @return: 0 for success, 1 for failure - **/ - int - initThrive(); - -#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) -#else - int main(int argc, char *argv[]) -#endif - { - if (initThrive() != 0){ - return -1; - } - using namespace thrive; - Game& game = Game::instance(); - game.run(); - return 0; - } - - int - initThrive(){ - std::ifstream versionFile("thriveversion.ver"); - std::ifstream mainLayout("../gui/layouts/MainMenu.layout"); - std::ofstream tempFile("../gui/layouts/MainMenuTemp.layout"); - - std::string version; - std::getline(versionFile, version); - - std::string str; - std::string needle = "" << '\n'; - continue; - //std::cout << "" << '\n'; - } - tempFile << str << '\n'; - } - versionFile.close(); - mainLayout.close(); - tempFile.close(); - - if( remove( "../gui/layouts/MainMenu.layout" ) != 0 ){ - perror( "Error deleting main menu layout" ); - return 1; - } - - int result = std::rename("../gui/layouts/MainMenuTemp.layout", "../gui/layouts/MainMenu.layout"); - if ( result != 0 ){ - perror( "Error renaming file" ); - return 1; - } - return 0; - - } - -#ifdef __cplusplus -} -#endif diff --git a/src/Main_Res.rc b/src/Main_Res.rc new file mode 100644 index 00000000000..8a0f44bc569 --- /dev/null +++ b/src/Main_Res.rc @@ -0,0 +1,13 @@ +// Generated by ResEdit 1.5.9 +// Copyright (C) 2006-2011 +// http://www.resedit.net + +#include +#include "resource.h" + + +// +// Icon resources +// +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +IDI_ICON1 ICON "../assets/misc/icon.ico" diff --git a/src/ThriveGame.cpp b/src/ThriveGame.cpp new file mode 100644 index 00000000000..b55a0af291f --- /dev/null +++ b/src/ThriveGame.cpp @@ -0,0 +1,1883 @@ +// ------------------------------------ // +#include "ThriveGame.h" + +#include "engine/player_data.h" +#include "general/locked_map.h" +#include "generated/cell_stage_world.h" +#include "generated/microbe_editor_world.h" +#include "main_menu_keypresses.h" +#include "microbe_stage/biome_controller.h" +#include "microbe_stage/player_microbe_control.h" +#include "microbe_stage/simulation_parameters.h" +#include "thrive_net_handler.h" +#include "thrive_version.h" +#include "thrive_world_factory.h" + +#include +#include +#include +#include +#include +#include +#include