diff options
| author | click <none@none> | 2010-06-05 21:22:47 +0200 |
|---|---|---|
| committer | click <none@none> | 2010-06-05 21:22:47 +0200 |
| commit | 455bfb01645510c677b88c693e0092244e1901e4 (patch) | |
| tree | f9a1d305217c4967fdd572b595a98e2f58a0c482 /src/server/shared | |
| parent | a2d6e7ff8c95e688adc625c01387af2ca3cde3a0 (diff) | |
Move core/realm files to new subdirectory
--HG--
branch : trunk
rename : src/framework/CMakeLists.txt => src/server/framework/CMakeLists.txt
rename : src/framework/Dynamic/FactoryHolder.h => src/server/framework/Dynamic/FactoryHolder.h
rename : src/framework/Dynamic/ObjectRegistry.h => src/server/framework/Dynamic/ObjectRegistry.h
rename : src/framework/GameSystem/Grid.h => src/server/framework/GameSystem/Grid.h
rename : src/framework/GameSystem/GridLoader.h => src/server/framework/GameSystem/GridLoader.h
rename : src/framework/GameSystem/GridRefManager.h => src/server/framework/GameSystem/GridRefManager.h
rename : src/framework/GameSystem/GridReference.h => src/server/framework/GameSystem/GridReference.h
rename : src/framework/GameSystem/NGrid.h => src/server/framework/GameSystem/NGrid.h
rename : src/framework/GameSystem/TypeContainer.h => src/server/framework/GameSystem/TypeContainer.h
rename : src/framework/GameSystem/TypeContainerFunctions.h => src/server/framework/GameSystem/TypeContainerFunctions.h
rename : src/framework/GameSystem/TypeContainerFunctionsPtr.h => src/server/framework/GameSystem/TypeContainerFunctionsPtr.h
rename : src/framework/GameSystem/TypeContainerVisitor.h => src/server/framework/GameSystem/TypeContainerVisitor.h
rename : src/framework/Network/SocketDefines.h => src/server/framework/Network/SocketDefines.h
rename : src/framework/Platform/CompilerDefs.h => src/server/framework/Platform/CompilerDefs.h
rename : src/framework/Platform/Define.h => src/server/framework/Platform/Define.h
rename : src/framework/Policies/CreationPolicy.h => src/server/framework/Policies/CreationPolicy.h
rename : src/framework/Policies/ObjectLifeTime.cpp => src/server/framework/Policies/ObjectLifeTime.cpp
rename : src/framework/Policies/ObjectLifeTime.h => src/server/framework/Policies/ObjectLifeTime.h
rename : src/framework/Policies/Singleton.h => src/server/framework/Policies/Singleton.h
rename : src/framework/Policies/SingletonImp.h => src/server/framework/Policies/SingletonImp.h
rename : src/framework/Policies/ThreadingModel.h => src/server/framework/Policies/ThreadingModel.h
rename : src/framework/Utilities/ByteConverter.h => src/server/framework/Utilities/ByteConverter.h
rename : src/framework/Utilities/Callback.h => src/server/framework/Utilities/Callback.h
rename : src/framework/Utilities/CountedReference/Reference.h => src/server/framework/Utilities/CountedReference/Reference.h
rename : src/framework/Utilities/CountedReference/ReferenceHolder.h => src/server/framework/Utilities/CountedReference/ReferenceHolder.h
rename : src/framework/Utilities/CountedReference/ReferenceImpl.h => src/server/framework/Utilities/CountedReference/ReferenceImpl.h
rename : src/framework/Utilities/EventProcessor.cpp => src/server/framework/Utilities/EventProcessor.cpp
rename : src/framework/Utilities/EventProcessor.h => src/server/framework/Utilities/EventProcessor.h
rename : src/framework/Utilities/LinkedList.h => src/server/framework/Utilities/LinkedList.h
rename : src/framework/Utilities/LinkedReference/RefManager.h => src/server/framework/Utilities/LinkedReference/RefManager.h
rename : src/framework/Utilities/LinkedReference/Reference.h => src/server/framework/Utilities/LinkedReference/Reference.h
rename : src/framework/Utilities/TypeList.h => src/server/framework/Utilities/TypeList.h
rename : src/framework/Utilities/UnorderedMap.h => src/server/framework/Utilities/UnorderedMap.h
rename : src/game/AccountMgr.cpp => src/server/game/AccountMgr.cpp
rename : src/game/AccountMgr.h => src/server/game/AccountMgr.h
rename : src/game/AchievementMgr.cpp => src/server/game/AchievementMgr.cpp
rename : src/game/AchievementMgr.h => src/server/game/AchievementMgr.h
rename : src/game/AddonHandler.cpp => src/server/game/AddonHandler.cpp
rename : src/game/AddonHandler.h => src/server/game/AddonHandler.h
rename : src/game/AddonMgr.cpp => src/server/game/AddonMgr.cpp
rename : src/game/AddonMgr.h => src/server/game/AddonMgr.h
rename : src/game/ArenaTeam.cpp => src/server/game/ArenaTeam.cpp
rename : src/game/ArenaTeam.h => src/server/game/ArenaTeam.h
rename : src/game/ArenaTeamHandler.cpp => src/server/game/ArenaTeamHandler.cpp
rename : src/game/AuctionHouseBot.cpp => src/server/game/AuctionHouseBot.cpp
rename : src/game/AuctionHouseBot.h => src/server/game/AuctionHouseBot.h
rename : src/game/AuctionHouseHandler.cpp => src/server/game/AuctionHouseHandler.cpp
rename : src/game/AuctionHouseMgr.cpp => src/server/game/AuctionHouseMgr.cpp
rename : src/game/AuctionHouseMgr.h => src/server/game/AuctionHouseMgr.h
rename : src/game/Bag.cpp => src/server/game/Bag.cpp
rename : src/game/Bag.h => src/server/game/Bag.h
rename : src/game/BattleGround.cpp => src/server/game/BattleGround.cpp
rename : src/game/BattleGround.h => src/server/game/BattleGround.h
rename : src/game/BattleGroundAA.cpp => src/server/game/BattleGroundAA.cpp
rename : src/game/BattleGroundAA.h => src/server/game/BattleGroundAA.h
rename : src/game/BattleGroundAB.cpp => src/server/game/BattleGroundAB.cpp
rename : src/game/BattleGroundAB.h => src/server/game/BattleGroundAB.h
rename : src/game/BattleGroundAV.cpp => src/server/game/BattleGroundAV.cpp
rename : src/game/BattleGroundAV.h => src/server/game/BattleGroundAV.h
rename : src/game/BattleGroundBE.cpp => src/server/game/BattleGroundBE.cpp
rename : src/game/BattleGroundBE.h => src/server/game/BattleGroundBE.h
rename : src/game/BattleGroundDS.cpp => src/server/game/BattleGroundDS.cpp
rename : src/game/BattleGroundDS.h => src/server/game/BattleGroundDS.h
rename : src/game/BattleGroundEY.cpp => src/server/game/BattleGroundEY.cpp
rename : src/game/BattleGroundEY.h => src/server/game/BattleGroundEY.h
rename : src/game/BattleGroundHandler.cpp => src/server/game/BattleGroundHandler.cpp
rename : src/game/BattleGroundIC.cpp => src/server/game/BattleGroundIC.cpp
rename : src/game/BattleGroundIC.h => src/server/game/BattleGroundIC.h
rename : src/game/BattleGroundMgr.cpp => src/server/game/BattleGroundMgr.cpp
rename : src/game/BattleGroundMgr.h => src/server/game/BattleGroundMgr.h
rename : src/game/BattleGroundNA.cpp => src/server/game/BattleGroundNA.cpp
rename : src/game/BattleGroundNA.h => src/server/game/BattleGroundNA.h
rename : src/game/BattleGroundRB.cpp => src/server/game/BattleGroundRB.cpp
rename : src/game/BattleGroundRB.h => src/server/game/BattleGroundRB.h
rename : src/game/BattleGroundRL.cpp => src/server/game/BattleGroundRL.cpp
rename : src/game/BattleGroundRL.h => src/server/game/BattleGroundRL.h
rename : src/game/BattleGroundRV.cpp => src/server/game/BattleGroundRV.cpp
rename : src/game/BattleGroundRV.h => src/server/game/BattleGroundRV.h
rename : src/game/BattleGroundSA.cpp => src/server/game/BattleGroundSA.cpp
rename : src/game/BattleGroundSA.h => src/server/game/BattleGroundSA.h
rename : src/game/BattleGroundWS.cpp => src/server/game/BattleGroundWS.cpp
rename : src/game/BattleGroundWS.h => src/server/game/BattleGroundWS.h
rename : src/game/CMakeLists.txt => src/server/game/CMakeLists.txt
rename : src/game/Calendar.cpp => src/server/game/Calendar.cpp
rename : src/game/Calendar.h => src/server/game/Calendar.h
rename : src/game/CalendarHandler.cpp => src/server/game/CalendarHandler.cpp
rename : src/game/Cell.h => src/server/game/Cell.h
rename : src/game/CellImpl.h => src/server/game/CellImpl.h
rename : src/game/Channel.cpp => src/server/game/Channel.cpp
rename : src/game/Channel.h => src/server/game/Channel.h
rename : src/game/ChannelHandler.cpp => src/server/game/ChannelHandler.cpp
rename : src/game/ChannelMgr.cpp => src/server/game/ChannelMgr.cpp
rename : src/game/ChannelMgr.h => src/server/game/ChannelMgr.h
rename : src/game/CharacterHandler.cpp => src/server/game/CharacterHandler.cpp
rename : src/game/Chat.cpp => src/server/game/Chat.cpp
rename : src/game/Chat.h => src/server/game/Chat.h
rename : src/game/ChatHandler.cpp => src/server/game/ChatHandler.cpp
rename : src/game/CombatAI.cpp => src/server/game/CombatAI.cpp
rename : src/game/CombatAI.h => src/server/game/CombatAI.h
rename : src/game/CombatHandler.cpp => src/server/game/CombatHandler.cpp
rename : src/game/ConditionMgr.cpp => src/server/game/ConditionMgr.cpp
rename : src/game/ConditionMgr.h => src/server/game/ConditionMgr.h
rename : src/game/ConfusedMovementGenerator.cpp => src/server/game/ConfusedMovementGenerator.cpp
rename : src/game/ConfusedMovementGenerator.h => src/server/game/ConfusedMovementGenerator.h
rename : src/game/Corpse.cpp => src/server/game/Corpse.cpp
rename : src/game/Corpse.h => src/server/game/Corpse.h
rename : src/game/Creature.cpp => src/server/game/Creature.cpp
rename : src/game/Creature.h => src/server/game/Creature.h
rename : src/game/CreatureAI.cpp => src/server/game/CreatureAI.cpp
rename : src/game/CreatureAI.h => src/server/game/CreatureAI.h
rename : src/game/CreatureAIFactory.h => src/server/game/CreatureAIFactory.h
rename : src/game/CreatureAIImpl.h => src/server/game/CreatureAIImpl.h
rename : src/game/CreatureAIRegistry.cpp => src/server/game/CreatureAIRegistry.cpp
rename : src/game/CreatureAIRegistry.h => src/server/game/CreatureAIRegistry.h
rename : src/game/CreatureAISelector.cpp => src/server/game/CreatureAISelector.cpp
rename : src/game/CreatureAISelector.h => src/server/game/CreatureAISelector.h
rename : src/game/CreatureEventAI.cpp => src/server/game/CreatureEventAI.cpp
rename : src/game/CreatureEventAI.h => src/server/game/CreatureEventAI.h
rename : src/game/CreatureEventAIMgr.cpp => src/server/game/CreatureEventAIMgr.cpp
rename : src/game/CreatureEventAIMgr.h => src/server/game/CreatureEventAIMgr.h
rename : src/game/CreatureGroups.cpp => src/server/game/CreatureGroups.cpp
rename : src/game/CreatureGroups.h => src/server/game/CreatureGroups.h
rename : src/game/DBCEnums.h => src/server/game/DBCEnums.h
rename : src/game/DBCStores.cpp => src/server/game/DBCStores.cpp
rename : src/game/DBCStores.h => src/server/game/DBCStores.h
rename : src/game/DBCStructure.h => src/server/game/DBCStructure.h
rename : src/game/DBCfmt.h => src/server/game/DBCfmt.h
rename : src/game/Debugcmds.cpp => src/server/game/Debugcmds.cpp
rename : src/game/DestinationHolder.cpp => src/server/game/DestinationHolder.cpp
rename : src/game/DestinationHolder.h => src/server/game/DestinationHolder.h
rename : src/game/DestinationHolderImp.h => src/server/game/DestinationHolderImp.h
rename : src/game/DuelHandler.cpp => src/server/game/DuelHandler.cpp
rename : src/game/DynamicObject.cpp => src/server/game/DynamicObject.cpp
rename : src/game/DynamicObject.h => src/server/game/DynamicObject.h
rename : src/game/FleeingMovementGenerator.cpp => src/server/game/FleeingMovementGenerator.cpp
rename : src/game/FleeingMovementGenerator.h => src/server/game/FleeingMovementGenerator.h
rename : src/game/FollowerRefManager.h => src/server/game/FollowerRefManager.h
rename : src/game/FollowerReference.cpp => src/server/game/FollowerReference.cpp
rename : src/game/FollowerReference.h => src/server/game/FollowerReference.h
rename : src/game/Formulas.h => src/server/game/Formulas.h
rename : src/game/GameEventMgr.cpp => src/server/game/GameEventMgr.cpp
rename : src/game/GameEventMgr.h => src/server/game/GameEventMgr.h
rename : src/game/GameObject.cpp => src/server/game/GameObject.cpp
rename : src/game/GameObject.h => src/server/game/GameObject.h
rename : src/game/GlobalEvents.cpp => src/server/game/GlobalEvents.cpp
rename : src/game/GlobalEvents.h => src/server/game/GlobalEvents.h
rename : src/game/GossipDef.cpp => src/server/game/GossipDef.cpp
rename : src/game/GossipDef.h => src/server/game/GossipDef.h
rename : src/game/GridDefines.h => src/server/game/GridDefines.h
rename : src/game/GridNotifiers.cpp => src/server/game/GridNotifiers.cpp
rename : src/game/GridNotifiers.h => src/server/game/GridNotifiers.h
rename : src/game/GridNotifiersImpl.h => src/server/game/GridNotifiersImpl.h
rename : src/game/GridStates.cpp => src/server/game/GridStates.cpp
rename : src/game/GridStates.h => src/server/game/GridStates.h
rename : src/game/Group.cpp => src/server/game/Group.cpp
rename : src/game/Group.h => src/server/game/Group.h
rename : src/game/GroupHandler.cpp => src/server/game/GroupHandler.cpp
rename : src/game/GroupRefManager.h => src/server/game/GroupRefManager.h
rename : src/game/GroupReference.cpp => src/server/game/GroupReference.cpp
rename : src/game/GroupReference.h => src/server/game/GroupReference.h
rename : src/game/GuardAI.cpp => src/server/game/GuardAI.cpp
rename : src/game/GuardAI.h => src/server/game/GuardAI.h
rename : src/game/Guild.cpp => src/server/game/Guild.cpp
rename : src/game/Guild.h => src/server/game/Guild.h
rename : src/game/GuildHandler.cpp => src/server/game/GuildHandler.cpp
rename : src/game/HomeMovementGenerator.cpp => src/server/game/HomeMovementGenerator.cpp
rename : src/game/HomeMovementGenerator.h => src/server/game/HomeMovementGenerator.h
rename : src/game/HostileRefManager.cpp => src/server/game/HostileRefManager.cpp
rename : src/game/HostileRefManager.h => src/server/game/HostileRefManager.h
rename : src/game/IdleMovementGenerator.cpp => src/server/game/IdleMovementGenerator.cpp
rename : src/game/IdleMovementGenerator.h => src/server/game/IdleMovementGenerator.h
rename : src/game/InstanceData.cpp => src/server/game/InstanceData.cpp
rename : src/game/InstanceData.h => src/server/game/InstanceData.h
rename : src/game/InstanceSaveMgr.cpp => src/server/game/InstanceSaveMgr.cpp
rename : src/game/InstanceSaveMgr.h => src/server/game/InstanceSaveMgr.h
rename : src/game/Item.cpp => src/server/game/Item.cpp
rename : src/game/Item.h => src/server/game/Item.h
rename : src/game/ItemEnchantmentMgr.cpp => src/server/game/ItemEnchantmentMgr.cpp
rename : src/game/ItemEnchantmentMgr.h => src/server/game/ItemEnchantmentMgr.h
rename : src/game/ItemHandler.cpp => src/server/game/ItemHandler.cpp
rename : src/game/ItemPrototype.h => src/server/game/ItemPrototype.h
rename : src/game/LFG.h => src/server/game/LFG.h
rename : src/game/LFGHandler.cpp => src/server/game/LFGHandler.cpp
rename : src/game/LFGMgr.cpp => src/server/game/LFGMgr.cpp
rename : src/game/LFGMgr.h => src/server/game/LFGMgr.h
rename : src/game/Language.h => src/server/game/Language.h
rename : src/game/Level0.cpp => src/server/game/Level0.cpp
rename : src/game/Level1.cpp => src/server/game/Level1.cpp
rename : src/game/Level2.cpp => src/server/game/Level2.cpp
rename : src/game/Level3.cpp => src/server/game/Level3.cpp
rename : src/game/LootHandler.cpp => src/server/game/LootHandler.cpp
rename : src/game/LootMgr.cpp => src/server/game/LootMgr.cpp
rename : src/game/LootMgr.h => src/server/game/LootMgr.h
rename : src/game/Mail.cpp => src/server/game/Mail.cpp
rename : src/game/Mail.h => src/server/game/Mail.h
rename : src/game/Map.cpp => src/server/game/Map.cpp
rename : src/game/Map.h => src/server/game/Map.h
rename : src/game/MapInstanced.cpp => src/server/game/MapInstanced.cpp
rename : src/game/MapInstanced.h => src/server/game/MapInstanced.h
rename : src/game/MapManager.cpp => src/server/game/MapManager.cpp
rename : src/game/MapManager.h => src/server/game/MapManager.h
rename : src/game/MapRefManager.h => src/server/game/MapRefManager.h
rename : src/game/MapReference.h => src/server/game/MapReference.h
rename : src/game/MapUpdater.cpp => src/server/game/MapUpdater.cpp
rename : src/game/MapUpdater.h => src/server/game/MapUpdater.h
rename : src/game/MiscHandler.cpp => src/server/game/MiscHandler.cpp
rename : src/game/MotionMaster.cpp => src/server/game/MotionMaster.cpp
rename : src/game/MotionMaster.h => src/server/game/MotionMaster.h
rename : src/game/MovementGenerator.cpp => src/server/game/MovementGenerator.cpp
rename : src/game/MovementGenerator.h => src/server/game/MovementGenerator.h
rename : src/game/MovementGeneratorImpl.h => src/server/game/MovementGeneratorImpl.h
rename : src/game/MovementHandler.cpp => src/server/game/MovementHandler.cpp
rename : src/game/NPCHandler.cpp => src/server/game/NPCHandler.cpp
rename : src/game/NPCHandler.h => src/server/game/NPCHandler.h
rename : src/game/Object.cpp => src/server/game/Object.cpp
rename : src/game/Object.h => src/server/game/Object.h
rename : src/game/ObjectAccessor.cpp => src/server/game/ObjectAccessor.cpp
rename : src/game/ObjectAccessor.h => src/server/game/ObjectAccessor.h
rename : src/game/ObjectDefines.h => src/server/game/ObjectDefines.h
rename : src/game/ObjectGridLoader.cpp => src/server/game/ObjectGridLoader.cpp
rename : src/game/ObjectGridLoader.h => src/server/game/ObjectGridLoader.h
rename : src/game/ObjectMgr.cpp => src/server/game/ObjectMgr.cpp
rename : src/game/ObjectMgr.h => src/server/game/ObjectMgr.h
rename : src/game/ObjectPosSelector.cpp => src/server/game/ObjectPosSelector.cpp
rename : src/game/ObjectPosSelector.h => src/server/game/ObjectPosSelector.h
rename : src/game/Opcodes.cpp => src/server/game/Opcodes.cpp
rename : src/game/Opcodes.h => src/server/game/Opcodes.h
rename : src/game/OutdoorPvP.cpp => src/server/game/OutdoorPvP.cpp
rename : src/game/OutdoorPvP.h => src/server/game/OutdoorPvP.h
rename : src/game/OutdoorPvPEP.cpp => src/server/game/OutdoorPvPEP.cpp
rename : src/game/OutdoorPvPEP.h => src/server/game/OutdoorPvPEP.h
rename : src/game/OutdoorPvPHP.cpp => src/server/game/OutdoorPvPHP.cpp
rename : src/game/OutdoorPvPHP.h => src/server/game/OutdoorPvPHP.h
rename : src/game/OutdoorPvPImpl.h => src/server/game/OutdoorPvPImpl.h
rename : src/game/OutdoorPvPMgr.cpp => src/server/game/OutdoorPvPMgr.cpp
rename : src/game/OutdoorPvPMgr.h => src/server/game/OutdoorPvPMgr.h
rename : src/game/OutdoorPvPNA.cpp => src/server/game/OutdoorPvPNA.cpp
rename : src/game/OutdoorPvPNA.h => src/server/game/OutdoorPvPNA.h
rename : src/game/OutdoorPvPSI.cpp => src/server/game/OutdoorPvPSI.cpp
rename : src/game/OutdoorPvPSI.h => src/server/game/OutdoorPvPSI.h
rename : src/game/OutdoorPvPTF.cpp => src/server/game/OutdoorPvPTF.cpp
rename : src/game/OutdoorPvPTF.h => src/server/game/OutdoorPvPTF.h
rename : src/game/OutdoorPvPZM.cpp => src/server/game/OutdoorPvPZM.cpp
rename : src/game/OutdoorPvPZM.h => src/server/game/OutdoorPvPZM.h
rename : src/game/PassiveAI.cpp => src/server/game/PassiveAI.cpp
rename : src/game/PassiveAI.h => src/server/game/PassiveAI.h
rename : src/game/Path.h => src/server/game/Path.h
rename : src/game/Pet.cpp => src/server/game/Pet.cpp
rename : src/game/Pet.h => src/server/game/Pet.h
rename : src/game/PetAI.cpp => src/server/game/PetAI.cpp
rename : src/game/PetAI.h => src/server/game/PetAI.h
rename : src/game/PetHandler.cpp => src/server/game/PetHandler.cpp
rename : src/game/PetitionsHandler.cpp => src/server/game/PetitionsHandler.cpp
rename : src/game/Player.cpp => src/server/game/Player.cpp
rename : src/game/Player.h => src/server/game/Player.h
rename : src/game/PlayerDump.cpp => src/server/game/PlayerDump.cpp
rename : src/game/PlayerDump.h => src/server/game/PlayerDump.h
rename : src/game/PointMovementGenerator.cpp => src/server/game/PointMovementGenerator.cpp
rename : src/game/PointMovementGenerator.h => src/server/game/PointMovementGenerator.h
rename : src/game/PoolHandler.cpp => src/server/game/PoolHandler.cpp
rename : src/game/PoolHandler.h => src/server/game/PoolHandler.h
rename : src/game/QueryHandler.cpp => src/server/game/QueryHandler.cpp
rename : src/game/QuestDef.cpp => src/server/game/QuestDef.cpp
rename : src/game/QuestDef.h => src/server/game/QuestDef.h
rename : src/game/QuestHandler.cpp => src/server/game/QuestHandler.cpp
rename : src/game/RandomMovementGenerator.cpp => src/server/game/RandomMovementGenerator.cpp
rename : src/game/RandomMovementGenerator.h => src/server/game/RandomMovementGenerator.h
rename : src/game/ReactorAI.cpp => src/server/game/ReactorAI.cpp
rename : src/game/ReactorAI.h => src/server/game/ReactorAI.h
rename : src/game/ReputationMgr.cpp => src/server/game/ReputationMgr.cpp
rename : src/game/ReputationMgr.h => src/server/game/ReputationMgr.h
rename : src/game/ScriptLoader.cpp => src/server/game/ScriptLoader.cpp
rename : src/game/ScriptLoader.h => src/server/game/ScriptLoader.h
rename : src/game/ScriptMgr.cpp => src/server/game/ScriptMgr.cpp
rename : src/game/ScriptMgr.h => src/server/game/ScriptMgr.h
rename : src/game/ScriptSystem.cpp => src/server/game/ScriptSystem.cpp
rename : src/game/ScriptSystem.h => src/server/game/ScriptSystem.h
rename : src/game/ScriptedCreature.cpp => src/server/game/ScriptedCreature.cpp
rename : src/game/ScriptedCreature.h => src/server/game/ScriptedCreature.h
rename : src/game/ScriptedEscortAI.cpp => src/server/game/ScriptedEscortAI.cpp
rename : src/game/ScriptedEscortAI.h => src/server/game/ScriptedEscortAI.h
rename : src/game/ScriptedFollowerAI.cpp => src/server/game/ScriptedFollowerAI.cpp
rename : src/game/ScriptedFollowerAI.h => src/server/game/ScriptedFollowerAI.h
rename : src/game/ScriptedGossip.h => src/server/game/ScriptedGossip.h
rename : src/game/ScriptedGuardAI.cpp => src/server/game/ScriptedGuardAI.cpp
rename : src/game/ScriptedGuardAI.h => src/server/game/ScriptedGuardAI.h
rename : src/game/ScriptedInstance.h => src/server/game/ScriptedInstance.h
rename : src/game/ScriptedPch.cpp => src/server/game/ScriptedPch.cpp
rename : src/game/ScriptedPch.h => src/server/game/ScriptedPch.h
rename : src/game/ScriptedSimpleAI.cpp => src/server/game/ScriptedSimpleAI.cpp
rename : src/game/ScriptedSimpleAI.h => src/server/game/ScriptedSimpleAI.h
rename : src/game/ScriptedSmartAI.cpp => src/server/game/ScriptedSmartAI.cpp
rename : src/game/ScriptedSmartAI.h => src/server/game/ScriptedSmartAI.h
rename : src/game/SharedDefines.h => src/server/game/SharedDefines.h
rename : src/game/SkillDiscovery.cpp => src/server/game/SkillDiscovery.cpp
rename : src/game/SkillDiscovery.h => src/server/game/SkillDiscovery.h
rename : src/game/SkillExtraItems.cpp => src/server/game/SkillExtraItems.cpp
rename : src/game/SkillExtraItems.h => src/server/game/SkillExtraItems.h
rename : src/game/SkillHandler.cpp => src/server/game/SkillHandler.cpp
rename : src/game/SocialMgr.cpp => src/server/game/SocialMgr.cpp
rename : src/game/SocialMgr.h => src/server/game/SocialMgr.h
rename : src/game/Spell.cpp => src/server/game/Spell.cpp
rename : src/game/Spell.h => src/server/game/Spell.h
rename : src/game/SpellAuraDefines.h => src/server/game/SpellAuraDefines.h
rename : src/game/SpellAuraEffects.cpp => src/server/game/SpellAuraEffects.cpp
rename : src/game/SpellAuraEffects.h => src/server/game/SpellAuraEffects.h
rename : src/game/SpellAuras.cpp => src/server/game/SpellAuras.cpp
rename : src/game/SpellAuras.h => src/server/game/SpellAuras.h
rename : src/game/SpellEffects.cpp => src/server/game/SpellEffects.cpp
rename : src/game/SpellHandler.cpp => src/server/game/SpellHandler.cpp
rename : src/game/SpellMgr.cpp => src/server/game/SpellMgr.cpp
rename : src/game/SpellMgr.h => src/server/game/SpellMgr.h
rename : src/game/StatSystem.cpp => src/server/game/StatSystem.cpp
rename : src/game/TargetedMovementGenerator.cpp => src/server/game/TargetedMovementGenerator.cpp
rename : src/game/TargetedMovementGenerator.h => src/server/game/TargetedMovementGenerator.h
rename : src/game/TaxiHandler.cpp => src/server/game/TaxiHandler.cpp
rename : src/game/TemporarySummon.cpp => src/server/game/TemporarySummon.cpp
rename : src/game/TemporarySummon.h => src/server/game/TemporarySummon.h
rename : src/game/ThreatManager.cpp => src/server/game/ThreatManager.cpp
rename : src/game/ThreatManager.h => src/server/game/ThreatManager.h
rename : src/game/TicketHandler.cpp => src/server/game/TicketHandler.cpp
rename : src/game/TimeMgr.cpp => src/server/game/TimeMgr.cpp
rename : src/game/TimeMgr.h => src/server/game/TimeMgr.h
rename : src/game/Tools.cpp => src/server/game/Tools.cpp
rename : src/game/Tools.h => src/server/game/Tools.h
rename : src/game/Totem.cpp => src/server/game/Totem.cpp
rename : src/game/Totem.h => src/server/game/Totem.h
rename : src/game/TotemAI.cpp => src/server/game/TotemAI.cpp
rename : src/game/TotemAI.h => src/server/game/TotemAI.h
rename : src/game/TradeHandler.cpp => src/server/game/TradeHandler.cpp
rename : src/game/Transports.cpp => src/server/game/Transports.cpp
rename : src/game/Transports.h => src/server/game/Transports.h
rename : src/game/Traveller.h => src/server/game/Traveller.h
rename : src/game/Unit.cpp => src/server/game/Unit.cpp
rename : src/game/Unit.h => src/server/game/Unit.h
rename : src/game/UnitAI.cpp => src/server/game/UnitAI.cpp
rename : src/game/UnitAI.h => src/server/game/UnitAI.h
rename : src/game/UnitEvents.h => src/server/game/UnitEvents.h
rename : src/game/UpdateData.cpp => src/server/game/UpdateData.cpp
rename : src/game/UpdateData.h => src/server/game/UpdateData.h
rename : src/game/UpdateFields.h => src/server/game/UpdateFields.h
rename : src/game/UpdateMask.h => src/server/game/UpdateMask.h
rename : src/game/Vehicle.cpp => src/server/game/Vehicle.cpp
rename : src/game/Vehicle.h => src/server/game/Vehicle.h
rename : src/game/VoiceChatHandler.cpp => src/server/game/VoiceChatHandler.cpp
rename : src/game/WaypointManager.cpp => src/server/game/WaypointManager.cpp
rename : src/game/WaypointManager.h => src/server/game/WaypointManager.h
rename : src/game/WaypointMovementGenerator.cpp => src/server/game/WaypointMovementGenerator.cpp
rename : src/game/WaypointMovementGenerator.h => src/server/game/WaypointMovementGenerator.h
rename : src/game/Weather.cpp => src/server/game/Weather.cpp
rename : src/game/Weather.h => src/server/game/Weather.h
rename : src/game/World.cpp => src/server/game/World.cpp
rename : src/game/World.h => src/server/game/World.h
rename : src/game/WorldLog.cpp => src/server/game/WorldLog.cpp
rename : src/game/WorldLog.h => src/server/game/WorldLog.h
rename : src/game/WorldSession.cpp => src/server/game/WorldSession.cpp
rename : src/game/WorldSession.h => src/server/game/WorldSession.h
rename : src/game/WorldSocket.cpp => src/server/game/WorldSocket.cpp
rename : src/game/WorldSocket.h => src/server/game/WorldSocket.h
rename : src/game/WorldSocketMgr.cpp => src/server/game/WorldSocketMgr.cpp
rename : src/game/WorldSocketMgr.h => src/server/game/WorldSocketMgr.h
rename : src/game/ZoneScript.h => src/server/game/ZoneScript.h
rename : src/game/pchdef.cpp => src/server/game/pchdef.cpp
rename : src/game/pchdef.h => src/server/game/pchdef.h
rename : src/game/pchlinux.cpp => src/server/game/pchlinux.cpp
rename : src/game/pchlinux.h => src/server/game/pchlinux.h
rename : src/scripts/CMakeLists.txt => src/server/scripts/CMakeLists.txt
rename : src/scripts/custom/custom_example.cpp => src/server/scripts/custom/custom_example.cpp
rename : src/scripts/custom/custom_gossip_codebox.cpp => src/server/scripts/custom/custom_gossip_codebox.cpp
rename : src/scripts/custom/npc_acherus_taxi.cpp => src/server/scripts/custom/npc_acherus_taxi.cpp
rename : src/scripts/custom/npc_wyrmresttempel_taxi.cpp => src/server/scripts/custom/npc_wyrmresttempel_taxi.cpp
rename : src/scripts/custom/on_events.cpp => src/server/scripts/custom/on_events.cpp
rename : src/scripts/custom/test.cpp => src/server/scripts/custom/test.cpp
rename : src/scripts/eastern_kingdoms/alterac_mountains.cpp => src/server/scripts/eastern_kingdoms/alterac_mountains.cpp
rename : src/scripts/eastern_kingdoms/alterac_valley/alterac_valley.cpp => src/server/scripts/eastern_kingdoms/alterac_valley/alterac_valley.cpp
rename : src/scripts/eastern_kingdoms/alterac_valley/boss_balinda.cpp => src/server/scripts/eastern_kingdoms/alterac_valley/boss_balinda.cpp
rename : src/scripts/eastern_kingdoms/alterac_valley/boss_drekthar.cpp => src/server/scripts/eastern_kingdoms/alterac_valley/boss_drekthar.cpp
rename : src/scripts/eastern_kingdoms/alterac_valley/boss_galvangar.cpp => src/server/scripts/eastern_kingdoms/alterac_valley/boss_galvangar.cpp
rename : src/scripts/eastern_kingdoms/alterac_valley/boss_vanndar.cpp => src/server/scripts/eastern_kingdoms/alterac_valley/boss_vanndar.cpp
rename : src/scripts/eastern_kingdoms/arathi_highlands.cpp => src/server/scripts/eastern_kingdoms/arathi_highlands.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h => src/server/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_anubshiah.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_anubshiah.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_gorosh_the_dervish.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_gorosh_the_dervish.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_grizzle.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_grizzle.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_magmus.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_magmus.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_moira_bronzebeard.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_moira_bronzebeard.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/boss_tomb_of_seven.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/boss_tomb_of_seven.cpp
rename : src/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp => src/server/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h => src/server/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_drakkisath.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_drakkisath.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_halycon.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_halycon.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_highlord_omokk.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_highlord_omokk.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_mother_smolderweb.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_mother_smolderweb.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_quartermaster_zigris.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_quartermaster_zigris.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_rend_blackhand.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_rend_blackhand.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_shadow_hunter_voshgajin.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_shadow_hunter_voshgajin.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_the_beast.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_the_beast.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/boss_warmaster_voone.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/boss_warmaster_voone.cpp
rename : src/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp => src/server/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp
rename : src/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp => src/server/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp
rename : src/scripts/eastern_kingdoms/blasted_lands.cpp => src/server/scripts/eastern_kingdoms/blasted_lands.cpp
rename : src/scripts/eastern_kingdoms/boss_kruul.cpp => src/server/scripts/eastern_kingdoms/boss_kruul.cpp
rename : src/scripts/eastern_kingdoms/burning_steppes.cpp => src/server/scripts/eastern_kingdoms/burning_steppes.cpp
rename : src/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp => src/server/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp
rename : src/scripts/eastern_kingdoms/deadmines/deadmines.cpp => src/server/scripts/eastern_kingdoms/deadmines/deadmines.cpp
rename : src/scripts/eastern_kingdoms/deadmines/deadmines.h => src/server/scripts/eastern_kingdoms/deadmines/deadmines.h
rename : src/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp => src/server/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp
rename : src/scripts/eastern_kingdoms/dun_morogh.cpp => src/server/scripts/eastern_kingdoms/dun_morogh.cpp
rename : src/scripts/eastern_kingdoms/duskwood.cpp => src/server/scripts/eastern_kingdoms/duskwood.cpp
rename : src/scripts/eastern_kingdoms/eastern_plaguelands.cpp => src/server/scripts/eastern_kingdoms/eastern_plaguelands.cpp
rename : src/scripts/eastern_kingdoms/elwynn_forest.cpp => src/server/scripts/eastern_kingdoms/elwynn_forest.cpp
rename : src/scripts/eastern_kingdoms/eversong_woods.cpp => src/server/scripts/eastern_kingdoms/eversong_woods.cpp
rename : src/scripts/eastern_kingdoms/ghostlands.cpp => src/server/scripts/eastern_kingdoms/ghostlands.cpp
rename : src/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp => src/server/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp
rename : src/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h => src/server/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h
rename : src/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp => src/server/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp
rename : src/scripts/eastern_kingdoms/hinterlands.cpp => src/server/scripts/eastern_kingdoms/hinterlands.cpp
rename : src/scripts/eastern_kingdoms/ironforge.cpp => src/server/scripts/eastern_kingdoms/ironforge.cpp
rename : src/scripts/eastern_kingdoms/isle_of_queldanas.cpp => src/server/scripts/eastern_kingdoms/isle_of_queldanas.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_curator.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_curator.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_prince_malchezaar.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_prince_malchezaar.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_shade_of_aran.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_shade_of_aran.cpp
rename : src/scripts/eastern_kingdoms/karazhan/boss_terestian_illhoof.cpp => src/server/scripts/eastern_kingdoms/karazhan/boss_terestian_illhoof.cpp
rename : src/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp => src/server/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp
rename : src/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp => src/server/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp
rename : src/scripts/eastern_kingdoms/karazhan/karazhan.cpp => src/server/scripts/eastern_kingdoms/karazhan/karazhan.cpp
rename : src/scripts/eastern_kingdoms/karazhan/karazhan.h => src/server/scripts/eastern_kingdoms/karazhan/karazhan.h
rename : src/scripts/eastern_kingdoms/loch_modan.cpp => src/server/scripts/eastern_kingdoms/loch_modan.cpp
rename : src/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp => src/server/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp
rename : src/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp => src/server/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp
rename : src/scripts/eastern_kingdoms/magisters_terrace/boss_selin_fireheart.cpp => src/server/scripts/eastern_kingdoms/magisters_terrace/boss_selin_fireheart.cpp
rename : src/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp => src/server/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp
rename : src/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp => src/server/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp
rename : src/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp => src/server/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp
rename : src/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h => src/server/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h
rename : src/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_garr.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_garr.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp
rename : src/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp => src/server/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp
rename : src/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp => src/server/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp
rename : src/scripts/eastern_kingdoms/molten_core/molten_core.cpp => src/server/scripts/eastern_kingdoms/molten_core/molten_core.cpp
rename : src/scripts/eastern_kingdoms/molten_core/molten_core.h => src/server/scripts/eastern_kingdoms/molten_core/molten_core.h
rename : src/scripts/eastern_kingdoms/redridge_mountains.cpp => src/server/scripts/eastern_kingdoms/redridge_mountains.cpp
rename : src/scripts/eastern_kingdoms/scarlet_enclave/chapter1.cpp => src/server/scripts/eastern_kingdoms/scarlet_enclave/chapter1.cpp
rename : src/scripts/eastern_kingdoms/scarlet_enclave/chapter2.cpp => src/server/scripts/eastern_kingdoms/scarlet_enclave/chapter2.cpp
rename : src/scripts/eastern_kingdoms/scarlet_enclave/chapter5.cpp => src/server/scripts/eastern_kingdoms/scarlet_enclave/chapter5.cpp
rename : src/scripts/eastern_kingdoms/scarlet_enclave/the_scarlet_enclave.cpp => src/server/scripts/eastern_kingdoms/scarlet_enclave/the_scarlet_enclave.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_arcanist_doan.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_arcanist_doan.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_azshir_the_sleepless.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_azshir_the_sleepless.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_bloodmage_thalnos.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_bloodmage_thalnos.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_herod.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_herod.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_houndmaster_loksey.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_houndmaster_loksey.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_interrogator_vishas.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_interrogator_vishas.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_mograine_and_whitemane.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_mograine_and_whitemane.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/boss_scorn.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/boss_scorn.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp => src/server/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp
rename : src/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h => src/server/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h
rename : src/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_death_knight_darkreaver.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_death_knight_darkreaver.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_doctor_theolen_krastinov.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_doctor_theolen_krastinov.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_illucia_barov.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_illucia_barov.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_instructor_malicia.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_instructor_malicia.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_kormok.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_kormok.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_lord_alexei_barov.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_lord_alexei_barov.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_lorekeeper_polkelt.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_lorekeeper_polkelt.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_ras_frostwhisper.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_ras_frostwhisper.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_the_ravenian.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_the_ravenian.cpp
rename : src/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp => src/server/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp
rename : src/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp => src/server/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp
rename : src/scripts/eastern_kingdoms/scholomance/scholomance.h => src/server/scripts/eastern_kingdoms/scholomance/scholomance.h
rename : src/scripts/eastern_kingdoms/searing_gorge.cpp => src/server/scripts/eastern_kingdoms/searing_gorge.cpp
rename : src/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp => src/server/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp
rename : src/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp => src/server/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp
rename : src/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h => src/server/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h
rename : src/scripts/eastern_kingdoms/silvermoon_city.cpp => src/server/scripts/eastern_kingdoms/silvermoon_city.cpp
rename : src/scripts/eastern_kingdoms/silverpine_forest.cpp => src/server/scripts/eastern_kingdoms/silverpine_forest.cpp
rename : src/scripts/eastern_kingdoms/stormwind_city.cpp => src/server/scripts/eastern_kingdoms/stormwind_city.cpp
rename : src/scripts/eastern_kingdoms/stranglethorn_vale.cpp => src/server/scripts/eastern_kingdoms/stranglethorn_vale.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_baron_rivendare.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_baron_rivendare.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_magistrate_barthilas.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_magistrate_barthilas.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_order_of_silver_hand.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_order_of_silver_hand.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_postmaster_malown.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_postmaster_malown.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_ramstein_the_gorger.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_ramstein_the_gorger.cpp
rename : src/scripts/eastern_kingdoms/stratholme/boss_timmy_the_cruel.cpp => src/server/scripts/eastern_kingdoms/stratholme/boss_timmy_the_cruel.cpp
rename : src/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp => src/server/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp
rename : src/scripts/eastern_kingdoms/stratholme/stratholme.cpp => src/server/scripts/eastern_kingdoms/stratholme/stratholme.cpp
rename : src/scripts/eastern_kingdoms/stratholme/stratholme.h => src/server/scripts/eastern_kingdoms/stratholme/stratholme.h
rename : src/scripts/eastern_kingdoms/sunken_temple/instance_sunken_temple.cpp => src/server/scripts/eastern_kingdoms/sunken_temple/instance_sunken_temple.cpp
rename : src/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp => src/server/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp
rename : src/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h => src/server/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h
rename : src/scripts/eastern_kingdoms/sunwell_plateau/boss_brutallus.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/boss_brutallus.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/boss_kalecgos.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/boss_kalecgos.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/boss_kiljaeden.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/boss_kiljaeden.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/boss_muru.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/boss_muru.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.cpp => src/server/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.cpp
rename : src/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h => src/server/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h
rename : src/scripts/eastern_kingdoms/tirisfal_glades.cpp => src/server/scripts/eastern_kingdoms/tirisfal_glades.cpp
rename : src/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp => src/server/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp
rename : src/scripts/eastern_kingdoms/uldaman/boss_ironaya.cpp => src/server/scripts/eastern_kingdoms/uldaman/boss_ironaya.cpp
rename : src/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp => src/server/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp
rename : src/scripts/eastern_kingdoms/uldaman/uldaman.cpp => src/server/scripts/eastern_kingdoms/uldaman/uldaman.cpp
rename : src/scripts/eastern_kingdoms/undercity.cpp => src/server/scripts/eastern_kingdoms/undercity.cpp
rename : src/scripts/eastern_kingdoms/western_plaguelands.cpp => src/server/scripts/eastern_kingdoms/western_plaguelands.cpp
rename : src/scripts/eastern_kingdoms/westfall.cpp => src/server/scripts/eastern_kingdoms/westfall.cpp
rename : src/scripts/eastern_kingdoms/wetlands.cpp => src/server/scripts/eastern_kingdoms/wetlands.cpp
rename : src/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp => src/server/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp
rename : src/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp => src/server/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp
rename : src/scripts/eastern_kingdoms/zulaman/boss_hexlord.cpp => src/server/scripts/eastern_kingdoms/zulaman/boss_hexlord.cpp
rename : src/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp => src/server/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp
rename : src/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp => src/server/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp
rename : src/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp => src/server/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp
rename : src/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp => src/server/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp
rename : src/scripts/eastern_kingdoms/zulaman/zulaman.cpp => src/server/scripts/eastern_kingdoms/zulaman/zulaman.cpp
rename : src/scripts/eastern_kingdoms/zulaman/zulaman.h => src/server/scripts/eastern_kingdoms/zulaman/zulaman.h
rename : src/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp => src/server/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp => src/server/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp
rename : src/scripts/eastern_kingdoms/zulgurub/zulgurub.h => src/server/scripts/eastern_kingdoms/zulgurub/zulgurub.h
rename : src/scripts/examples/example_creature.cpp => src/server/scripts/examples/example_creature.cpp
rename : src/scripts/examples/example_escort.cpp => src/server/scripts/examples/example_escort.cpp
rename : src/scripts/examples/example_gossip_codebox.cpp => src/server/scripts/examples/example_gossip_codebox.cpp
rename : src/scripts/examples/example_misc.cpp => src/server/scripts/examples/example_misc.cpp
rename : src/scripts/kalimdor/ashenvale.cpp => src/server/scripts/kalimdor/ashenvale.cpp
rename : src/scripts/kalimdor/azshara.cpp => src/server/scripts/kalimdor/azshara.cpp
rename : src/scripts/kalimdor/azuremyst_isle.cpp => src/server/scripts/kalimdor/azuremyst_isle.cpp
rename : src/scripts/kalimdor/blackfathom_depths/blackfathom_deeps.cpp => src/server/scripts/kalimdor/blackfathom_depths/blackfathom_deeps.cpp
rename : src/scripts/kalimdor/blackfathom_depths/blackfathom_deeps.h => src/server/scripts/kalimdor/blackfathom_depths/blackfathom_deeps.h
rename : src/scripts/kalimdor/blackfathom_depths/boss_aku_mai.cpp => src/server/scripts/kalimdor/blackfathom_depths/boss_aku_mai.cpp
rename : src/scripts/kalimdor/blackfathom_depths/boss_gelihast.cpp => src/server/scripts/kalimdor/blackfathom_depths/boss_gelihast.cpp
rename : src/scripts/kalimdor/blackfathom_depths/boss_kelris.cpp => src/server/scripts/kalimdor/blackfathom_depths/boss_kelris.cpp
rename : src/scripts/kalimdor/blackfathom_depths/instance_blackfathom_deeps.cpp => src/server/scripts/kalimdor/blackfathom_depths/instance_blackfathom_deeps.cpp
rename : src/scripts/kalimdor/bloodmyst_isle.cpp => src/server/scripts/kalimdor/bloodmyst_isle.cpp
rename : src/scripts/kalimdor/boss_azuregos.cpp => src/server/scripts/kalimdor/boss_azuregos.cpp
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_epoch.cpp => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_epoch.cpp
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_infinite.cpp => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_infinite.cpp
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_mal_ganis.cpp => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_mal_ganis.cpp
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_meathook.cpp => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_meathook.cpp
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_salramm.cpp => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/boss_salramm.cpp
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.cpp => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.cpp
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.h => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.h
rename : src/scripts/kalimdor/caverns_of_time/culling_of_stratholme/instance_culling_of_stratholme.cpp => src/server/scripts/kalimdor/caverns_of_time/culling_of_stratholme/instance_culling_of_stratholme.cpp
rename : src/scripts/kalimdor/caverns_of_time/dark_portal/boss_aeonus.cpp => src/server/scripts/kalimdor/caverns_of_time/dark_portal/boss_aeonus.cpp
rename : src/scripts/kalimdor/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp => src/server/scripts/kalimdor/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp
rename : src/scripts/kalimdor/caverns_of_time/dark_portal/boss_temporus.cpp => src/server/scripts/kalimdor/caverns_of_time/dark_portal/boss_temporus.cpp
rename : src/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.cpp => src/server/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.cpp
rename : src/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.h => src/server/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.h
rename : src/scripts/kalimdor/caverns_of_time/dark_portal/instance_dark_portal.cpp => src/server/scripts/kalimdor/caverns_of_time/dark_portal/instance_dark_portal.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/boss_anetheron.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/boss_anetheron.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/boss_azgalor.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/boss_azgalor.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/boss_kazrogal.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/boss_kazrogal.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/boss_rage_winterchill.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/boss_rage_winterchill.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h => src/server/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h
rename : src/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h => src/server/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h
rename : src/scripts/kalimdor/caverns_of_time/hyjal/hyjal_trash.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/hyjal_trash.cpp
rename : src/scripts/kalimdor/caverns_of_time/hyjal/hyjal_trash.h => src/server/scripts/kalimdor/caverns_of_time/hyjal/hyjal_trash.h
rename : src/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp => src/server/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp
rename : src/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp => src/server/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp
rename : src/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp => src/server/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp
rename : src/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp => src/server/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp
rename : src/scripts/kalimdor/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp => src/server/scripts/kalimdor/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp
rename : src/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp => src/server/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp
rename : src/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.h => src/server/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.h
rename : src/scripts/kalimdor/darkshore.cpp => src/server/scripts/kalimdor/darkshore.cpp
rename : src/scripts/kalimdor/desolace.cpp => src/server/scripts/kalimdor/desolace.cpp
rename : src/scripts/kalimdor/durotar.cpp => src/server/scripts/kalimdor/durotar.cpp
rename : src/scripts/kalimdor/dustwallow_marsh.cpp => src/server/scripts/kalimdor/dustwallow_marsh.cpp
rename : src/scripts/kalimdor/felwood.cpp => src/server/scripts/kalimdor/felwood.cpp
rename : src/scripts/kalimdor/feralas.cpp => src/server/scripts/kalimdor/feralas.cpp
rename : src/scripts/kalimdor/maraudon/boss_celebras_the_cursed.cpp => src/server/scripts/kalimdor/maraudon/boss_celebras_the_cursed.cpp
rename : src/scripts/kalimdor/maraudon/boss_landslide.cpp => src/server/scripts/kalimdor/maraudon/boss_landslide.cpp
rename : src/scripts/kalimdor/maraudon/boss_noxxion.cpp => src/server/scripts/kalimdor/maraudon/boss_noxxion.cpp
rename : src/scripts/kalimdor/maraudon/boss_princess_theradras.cpp => src/server/scripts/kalimdor/maraudon/boss_princess_theradras.cpp
rename : src/scripts/kalimdor/moonglade.cpp => src/server/scripts/kalimdor/moonglade.cpp
rename : src/scripts/kalimdor/mulgore.cpp => src/server/scripts/kalimdor/mulgore.cpp
rename : src/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp => src/server/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp
rename : src/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp => src/server/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp
rename : src/scripts/kalimdor/onyxias_lair/onyxias_lair.h => src/server/scripts/kalimdor/onyxias_lair/onyxias_lair.h
rename : src/scripts/kalimdor/orgrimmar.cpp => src/server/scripts/kalimdor/orgrimmar.cpp
rename : src/scripts/kalimdor/razorfen_downs/boss_amnennar_the_coldbringer.cpp => src/server/scripts/kalimdor/razorfen_downs/boss_amnennar_the_coldbringer.cpp
rename : src/scripts/kalimdor/razorfen_downs/instance_razorfen_downs.cpp => src/server/scripts/kalimdor/razorfen_downs/instance_razorfen_downs.cpp
rename : src/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp => src/server/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp
rename : src/scripts/kalimdor/razorfen_downs/razorfen_downs.h => src/server/scripts/kalimdor/razorfen_downs/razorfen_downs.h
rename : src/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp => src/server/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp
rename : src/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp => src/server/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp
rename : src/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h => src/server/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp => src/server/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp => src/server/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp => src/server/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp => src/server/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp => src/server/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp => src/server/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp => src/server/scripts/kalimdor/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp
rename : src/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h => src/server/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h
rename : src/scripts/kalimdor/silithus.cpp => src/server/scripts/kalimdor/silithus.cpp
rename : src/scripts/kalimdor/stonetalon_mountains.cpp => src/server/scripts/kalimdor/stonetalon_mountains.cpp
rename : src/scripts/kalimdor/tanaris.cpp => src/server/scripts/kalimdor/tanaris.cpp
rename : src/scripts/kalimdor/teldrassil.cpp => src/server/scripts/kalimdor/teldrassil.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_fankriss.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_fankriss.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_sartura.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_sartura.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_twinemperors.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_twinemperors.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp => src/server/scripts/kalimdor/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp
rename : src/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h => src/server/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h
rename : src/scripts/kalimdor/the_barrens.cpp => src/server/scripts/kalimdor/the_barrens.cpp
rename : src/scripts/kalimdor/thousand_needles.cpp => src/server/scripts/kalimdor/thousand_needles.cpp
rename : src/scripts/kalimdor/thunder_bluff.cpp => src/server/scripts/kalimdor/thunder_bluff.cpp
rename : src/scripts/kalimdor/ungoro_crater.cpp => src/server/scripts/kalimdor/ungoro_crater.cpp
rename : src/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp => src/server/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp
rename : src/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp => src/server/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp
rename : src/scripts/kalimdor/wailing_caverns/wailing_caverns.h => src/server/scripts/kalimdor/wailing_caverns/wailing_caverns.h
rename : src/scripts/kalimdor/winterspring.cpp => src/server/scripts/kalimdor/winterspring.cpp
rename : src/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp => src/server/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp
rename : src/scripts/kalimdor/zulfarrak/zulfarrak.cpp => src/server/scripts/kalimdor/zulfarrak/zulfarrak.cpp
rename : src/scripts/northrend/azjol_nerub/ahnkahet/ahnkahet.h => src/server/scripts/northrend/azjol_nerub/ahnkahet/ahnkahet.h
rename : src/scripts/northrend/azjol_nerub/ahnkahet/boss_amanitar.cpp => src/server/scripts/northrend/azjol_nerub/ahnkahet/boss_amanitar.cpp
rename : src/scripts/northrend/azjol_nerub/ahnkahet/boss_elder_nadox.cpp => src/server/scripts/northrend/azjol_nerub/ahnkahet/boss_elder_nadox.cpp
rename : src/scripts/northrend/azjol_nerub/ahnkahet/boss_herald_volazj.cpp => src/server/scripts/northrend/azjol_nerub/ahnkahet/boss_herald_volazj.cpp
rename : src/scripts/northrend/azjol_nerub/ahnkahet/boss_jedoga_shadowseeker.cpp => src/server/scripts/northrend/azjol_nerub/ahnkahet/boss_jedoga_shadowseeker.cpp
rename : src/scripts/northrend/azjol_nerub/ahnkahet/boss_prince_taldaram.cpp => src/server/scripts/northrend/azjol_nerub/ahnkahet/boss_prince_taldaram.cpp
rename : src/scripts/northrend/azjol_nerub/ahnkahet/instance_ahnkahet.cpp => src/server/scripts/northrend/azjol_nerub/ahnkahet/instance_ahnkahet.cpp
rename : src/scripts/northrend/azjol_nerub/azjol_nerub/azjol_nerub.h => src/server/scripts/northrend/azjol_nerub/azjol_nerub/azjol_nerub.h
rename : src/scripts/northrend/azjol_nerub/azjol_nerub/boss_anubarak.cpp => src/server/scripts/northrend/azjol_nerub/azjol_nerub/boss_anubarak.cpp
rename : src/scripts/northrend/azjol_nerub/azjol_nerub/boss_hadronox.cpp => src/server/scripts/northrend/azjol_nerub/azjol_nerub/boss_hadronox.cpp
rename : src/scripts/northrend/azjol_nerub/azjol_nerub/boss_krikthir_the_gatewatcher.cpp => src/server/scripts/northrend/azjol_nerub/azjol_nerub/boss_krikthir_the_gatewatcher.cpp
rename : src/scripts/northrend/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp => src/server/scripts/northrend/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp
rename : src/scripts/northrend/borean_tundra.cpp => src/server/scripts/northrend/borean_tundra.cpp
rename : src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp => src/server/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp
rename : src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp => src/server/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp
rename : src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp => src/server/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp
rename : src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp => src/server/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp
rename : src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp => src/server/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp
rename : src/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h => src/server/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h
rename : src/scripts/northrend/crystalsong_forest.cpp => src/server/scripts/northrend/crystalsong_forest.cpp
rename : src/scripts/northrend/dalaran.cpp => src/server/scripts/northrend/dalaran.cpp
rename : src/scripts/northrend/dragonblight.cpp => src/server/scripts/northrend/dragonblight.cpp
rename : src/scripts/northrend/draktharon_keep/boss_dred.cpp => src/server/scripts/northrend/draktharon_keep/boss_dred.cpp
rename : src/scripts/northrend/draktharon_keep/boss_novos.cpp => src/server/scripts/northrend/draktharon_keep/boss_novos.cpp
rename : src/scripts/northrend/draktharon_keep/boss_tharon_ja.cpp => src/server/scripts/northrend/draktharon_keep/boss_tharon_ja.cpp
rename : src/scripts/northrend/draktharon_keep/boss_trollgore.cpp => src/server/scripts/northrend/draktharon_keep/boss_trollgore.cpp
rename : src/scripts/northrend/draktharon_keep/drak_tharon_keep.h => src/server/scripts/northrend/draktharon_keep/drak_tharon_keep.h
rename : src/scripts/northrend/draktharon_keep/instance_drak_tharon_keep.cpp => src/server/scripts/northrend/draktharon_keep/instance_drak_tharon_keep.cpp
rename : src/scripts/northrend/frozen_halls/forge_of_souls/boss_bronjahm.cpp => src/server/scripts/northrend/frozen_halls/forge_of_souls/boss_bronjahm.cpp
rename : src/scripts/northrend/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp => src/server/scripts/northrend/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp
rename : src/scripts/northrend/frozen_halls/forge_of_souls/forge_of_souls.cpp => src/server/scripts/northrend/frozen_halls/forge_of_souls/forge_of_souls.cpp
rename : src/scripts/northrend/frozen_halls/forge_of_souls/forge_of_souls.h => src/server/scripts/northrend/frozen_halls/forge_of_souls/forge_of_souls.h
rename : src/scripts/northrend/frozen_halls/forge_of_souls/instance_forge_of_souls.cpp => src/server/scripts/northrend/frozen_halls/forge_of_souls/instance_forge_of_souls.cpp
rename : src/scripts/northrend/frozen_halls/halls_of_reflection/boss_falric.cpp => src/server/scripts/northrend/frozen_halls/halls_of_reflection/boss_falric.cpp
rename : src/scripts/northrend/frozen_halls/halls_of_reflection/boss_marwyn.cpp => src/server/scripts/northrend/frozen_halls/halls_of_reflection/boss_marwyn.cpp
rename : src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.cpp => src/server/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.cpp
rename : src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h => src/server/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h
rename : src/scripts/northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp => src/server/scripts/northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp
rename : src/scripts/northrend/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp => src/server/scripts/northrend/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp
rename : src/scripts/northrend/frozen_halls/pit_of_saron/boss_krickandick.cpp => src/server/scripts/northrend/frozen_halls/pit_of_saron/boss_krickandick.cpp
rename : src/scripts/northrend/frozen_halls/pit_of_saron/boss_scourgelord_tyrannus.cpp => src/server/scripts/northrend/frozen_halls/pit_of_saron/boss_scourgelord_tyrannus.cpp
rename : src/scripts/northrend/frozen_halls/pit_of_saron/instance_pit_of_saron.cpp => src/server/scripts/northrend/frozen_halls/pit_of_saron/instance_pit_of_saron.cpp
rename : src/scripts/northrend/frozen_halls/pit_of_saron/pit_of_saron.cpp => src/server/scripts/northrend/frozen_halls/pit_of_saron/pit_of_saron.cpp
rename : src/scripts/northrend/frozen_halls/pit_of_saron/pit_of_saron.h => src/server/scripts/northrend/frozen_halls/pit_of_saron/pit_of_saron.h
rename : src/scripts/northrend/grizzly_hills.cpp => src/server/scripts/northrend/grizzly_hills.cpp
rename : src/scripts/northrend/gundrak/boss_drakkari_colossus.cpp => src/server/scripts/northrend/gundrak/boss_drakkari_colossus.cpp
rename : src/scripts/northrend/gundrak/boss_eck.cpp => src/server/scripts/northrend/gundrak/boss_eck.cpp
rename : src/scripts/northrend/gundrak/boss_gal_darah.cpp => src/server/scripts/northrend/gundrak/boss_gal_darah.cpp
rename : src/scripts/northrend/gundrak/boss_moorabi.cpp => src/server/scripts/northrend/gundrak/boss_moorabi.cpp
rename : src/scripts/northrend/gundrak/boss_slad_ran.cpp => src/server/scripts/northrend/gundrak/boss_slad_ran.cpp
rename : src/scripts/northrend/gundrak/gundrak.h => src/server/scripts/northrend/gundrak/gundrak.h
rename : src/scripts/northrend/gundrak/instance_gundrak.cpp => src/server/scripts/northrend/gundrak/instance_gundrak.cpp
rename : src/scripts/northrend/howling_fjord.cpp => src/server/scripts/northrend/howling_fjord.cpp
rename : src/scripts/northrend/icecrown.cpp => src/server/scripts/northrend/icecrown.cpp
rename : src/scripts/northrend/naxxramas/boss_anubrekhan.cpp => src/server/scripts/northrend/naxxramas/boss_anubrekhan.cpp
rename : src/scripts/northrend/naxxramas/boss_faerlina.cpp => src/server/scripts/northrend/naxxramas/boss_faerlina.cpp
rename : src/scripts/northrend/naxxramas/boss_four_horsemen.cpp => src/server/scripts/northrend/naxxramas/boss_four_horsemen.cpp
rename : src/scripts/northrend/naxxramas/boss_gluth.cpp => src/server/scripts/northrend/naxxramas/boss_gluth.cpp
rename : src/scripts/northrend/naxxramas/boss_gothik.cpp => src/server/scripts/northrend/naxxramas/boss_gothik.cpp
rename : src/scripts/northrend/naxxramas/boss_grobbulus.cpp => src/server/scripts/northrend/naxxramas/boss_grobbulus.cpp
rename : src/scripts/northrend/naxxramas/boss_heigan.cpp => src/server/scripts/northrend/naxxramas/boss_heigan.cpp
rename : src/scripts/northrend/naxxramas/boss_highlord_mograine.cpp => src/server/scripts/northrend/naxxramas/boss_highlord_mograine.cpp
rename : src/scripts/northrend/naxxramas/boss_kelthuzad.cpp => src/server/scripts/northrend/naxxramas/boss_kelthuzad.cpp
rename : src/scripts/northrend/naxxramas/boss_loatheb.cpp => src/server/scripts/northrend/naxxramas/boss_loatheb.cpp
rename : src/scripts/northrend/naxxramas/boss_maexxna.cpp => src/server/scripts/northrend/naxxramas/boss_maexxna.cpp
rename : src/scripts/northrend/naxxramas/boss_noth.cpp => src/server/scripts/northrend/naxxramas/boss_noth.cpp
rename : src/scripts/northrend/naxxramas/boss_patchwerk.cpp => src/server/scripts/northrend/naxxramas/boss_patchwerk.cpp
rename : src/scripts/northrend/naxxramas/boss_razuvious.cpp => src/server/scripts/northrend/naxxramas/boss_razuvious.cpp
rename : src/scripts/northrend/naxxramas/boss_sapphiron.cpp => src/server/scripts/northrend/naxxramas/boss_sapphiron.cpp
rename : src/scripts/northrend/naxxramas/boss_thaddius.cpp => src/server/scripts/northrend/naxxramas/boss_thaddius.cpp
rename : src/scripts/northrend/naxxramas/instance_naxxramas.cpp => src/server/scripts/northrend/naxxramas/instance_naxxramas.cpp
rename : src/scripts/northrend/naxxramas/naxxramas.h => src/server/scripts/northrend/naxxramas/naxxramas.h
rename : src/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp => src/server/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp
rename : src/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h => src/server/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h
rename : src/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp => src/server/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp
rename : src/scripts/northrend/nexus/nexus/boss_anomalus.cpp => src/server/scripts/northrend/nexus/nexus/boss_anomalus.cpp
rename : src/scripts/northrend/nexus/nexus/boss_keristrasza.cpp => src/server/scripts/northrend/nexus/nexus/boss_keristrasza.cpp
rename : src/scripts/northrend/nexus/nexus/boss_magus_telestra.cpp => src/server/scripts/northrend/nexus/nexus/boss_magus_telestra.cpp
rename : src/scripts/northrend/nexus/nexus/boss_ormorok.cpp => src/server/scripts/northrend/nexus/nexus/boss_ormorok.cpp
rename : src/scripts/northrend/nexus/nexus/commander_kolurg.cpp => src/server/scripts/northrend/nexus/nexus/commander_kolurg.cpp
rename : src/scripts/northrend/nexus/nexus/commander_stoutbeard.cpp => src/server/scripts/northrend/nexus/nexus/commander_stoutbeard.cpp
rename : src/scripts/northrend/nexus/nexus/instance_nexus.cpp => src/server/scripts/northrend/nexus/nexus/instance_nexus.cpp
rename : src/scripts/northrend/nexus/nexus/nexus.h => src/server/scripts/northrend/nexus/nexus/nexus.h
rename : src/scripts/northrend/nexus/oculus/boss_drakos.cpp => src/server/scripts/northrend/nexus/oculus/boss_drakos.cpp
rename : src/scripts/northrend/nexus/oculus/boss_eregos.cpp => src/server/scripts/northrend/nexus/oculus/boss_eregos.cpp
rename : src/scripts/northrend/nexus/oculus/boss_urom.cpp => src/server/scripts/northrend/nexus/oculus/boss_urom.cpp
rename : src/scripts/northrend/nexus/oculus/boss_varos.cpp => src/server/scripts/northrend/nexus/oculus/boss_varos.cpp
rename : src/scripts/northrend/nexus/oculus/instance_oculus.cpp => src/server/scripts/northrend/nexus/oculus/instance_oculus.cpp
rename : src/scripts/northrend/nexus/oculus/oculus.cpp => src/server/scripts/northrend/nexus/oculus/oculus.cpp
rename : src/scripts/northrend/nexus/oculus/oculus.h => src/server/scripts/northrend/nexus/oculus/oculus.h
rename : src/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp => src/server/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp
rename : src/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp => src/server/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp
rename : src/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h => src/server/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h
rename : src/scripts/northrend/sholazar_basin.cpp => src/server/scripts/northrend/sholazar_basin.cpp
rename : src/scripts/northrend/storm_peaks.cpp => src/server/scripts/northrend/storm_peaks.cpp
rename : src/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp => src/server/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp
rename : src/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp => src/server/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp
rename : src/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp => src/server/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp
rename : src/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp => src/server/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp
rename : src/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h => src/server/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h
rename : src/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp => src/server/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp
rename : src/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp => src/server/scripts/northrend/ulduar/halls_of_stone/boss_krystallus.cpp
rename : src/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp => src/server/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp
rename : src/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp => src/server/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp
rename : src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp => src/server/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp
rename : src/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h => src/server/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h
rename : src/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp => src/server/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_algalon.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_algalon.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_assembly_of_iron.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_assembly_of_iron.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_freya.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_freya.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_hodir.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_hodir.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_ignis.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_ignis.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_thorim.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_thorim.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_xt002.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_xt002.cpp
rename : src/scripts/northrend/ulduar/ulduar/boss_yoggsaron.cpp => src/server/scripts/northrend/ulduar/ulduar/boss_yoggsaron.cpp
rename : src/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp => src/server/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp
rename : src/scripts/northrend/ulduar/ulduar/ulduar.h => src/server/scripts/northrend/ulduar/ulduar/ulduar.h
rename : src/scripts/northrend/ulduar/ulduar/ulduar_teleporter.cpp => src/server/scripts/northrend/ulduar/ulduar/ulduar_teleporter.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h => src/server/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h
rename : src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_palehoof.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_palehoof.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_pinnacle.cpp => src/server/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_pinnacle.cpp
rename : src/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h => src/server/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h
rename : src/scripts/northrend/vault_of_archavon/boss_archavon.cpp => src/server/scripts/northrend/vault_of_archavon/boss_archavon.cpp
rename : src/scripts/northrend/vault_of_archavon/boss_emalon.cpp => src/server/scripts/northrend/vault_of_archavon/boss_emalon.cpp
rename : src/scripts/northrend/vault_of_archavon/boss_koralon.cpp => src/server/scripts/northrend/vault_of_archavon/boss_koralon.cpp
rename : src/scripts/northrend/vault_of_archavon/boss_toravon.cpp => src/server/scripts/northrend/vault_of_archavon/boss_toravon.cpp
rename : src/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp => src/server/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp
rename : src/scripts/northrend/vault_of_archavon/vault_of_archavon.h => src/server/scripts/northrend/vault_of_archavon/vault_of_archavon.h
rename : src/scripts/northrend/violet_hold/boss_cyanigosa.cpp => src/server/scripts/northrend/violet_hold/boss_cyanigosa.cpp
rename : src/scripts/northrend/violet_hold/boss_erekem.cpp => src/server/scripts/northrend/violet_hold/boss_erekem.cpp
rename : src/scripts/northrend/violet_hold/boss_ichoron.cpp => src/server/scripts/northrend/violet_hold/boss_ichoron.cpp
rename : src/scripts/northrend/violet_hold/boss_lavanthor.cpp => src/server/scripts/northrend/violet_hold/boss_lavanthor.cpp
rename : src/scripts/northrend/violet_hold/boss_moragg.cpp => src/server/scripts/northrend/violet_hold/boss_moragg.cpp
rename : src/scripts/northrend/violet_hold/boss_xevozz.cpp => src/server/scripts/northrend/violet_hold/boss_xevozz.cpp
rename : src/scripts/northrend/violet_hold/boss_zuramat.cpp => src/server/scripts/northrend/violet_hold/boss_zuramat.cpp
rename : src/scripts/northrend/violet_hold/instance_violet_hold.cpp => src/server/scripts/northrend/violet_hold/instance_violet_hold.cpp
rename : src/scripts/northrend/violet_hold/violet_hold.cpp => src/server/scripts/northrend/violet_hold/violet_hold.cpp
rename : src/scripts/northrend/violet_hold/violet_hold.h => src/server/scripts/northrend/violet_hold/violet_hold.h
rename : src/scripts/northrend/zuldrak.cpp => src/server/scripts/northrend/zuldrak.cpp
rename : src/scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp => src/server/scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp
rename : src/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak_the_dead_watcher.cpp => src/server/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak_the_dead_watcher.cpp
rename : src/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp => src/server/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp
rename : src/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp => src/server/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp
rename : src/scripts/outland/auchindoun/sethekk_halls/boss_darkweaver_syth.cpp => src/server/scripts/outland/auchindoun/sethekk_halls/boss_darkweaver_syth.cpp
rename : src/scripts/outland/auchindoun/sethekk_halls/boss_tailonking_ikiss.cpp => src/server/scripts/outland/auchindoun/sethekk_halls/boss_tailonking_ikiss.cpp
rename : src/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp => src/server/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp
rename : src/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h => src/server/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h
rename : src/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp => src/server/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp
rename : src/scripts/outland/auchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp => src/server/scripts/outland/auchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp
rename : src/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp => src/server/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp
rename : src/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp => src/server/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp
rename : src/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp => src/server/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp
rename : src/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h => src/server/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h
rename : src/scripts/outland/black_temple/black_temple.cpp => src/server/scripts/outland/black_temple/black_temple.cpp
rename : src/scripts/outland/black_temple/black_temple.h => src/server/scripts/outland/black_temple/black_temple.h
rename : src/scripts/outland/black_temple/boss_bloodboil.cpp => src/server/scripts/outland/black_temple/boss_bloodboil.cpp
rename : src/scripts/outland/black_temple/boss_illidan.cpp => src/server/scripts/outland/black_temple/boss_illidan.cpp
rename : src/scripts/outland/black_temple/boss_mother_shahraz.cpp => src/server/scripts/outland/black_temple/boss_mother_shahraz.cpp
rename : src/scripts/outland/black_temple/boss_reliquary_of_souls.cpp => src/server/scripts/outland/black_temple/boss_reliquary_of_souls.cpp
rename : src/scripts/outland/black_temple/boss_shade_of_akama.cpp => src/server/scripts/outland/black_temple/boss_shade_of_akama.cpp
rename : src/scripts/outland/black_temple/boss_supremus.cpp => src/server/scripts/outland/black_temple/boss_supremus.cpp
rename : src/scripts/outland/black_temple/boss_teron_gorefiend.cpp => src/server/scripts/outland/black_temple/boss_teron_gorefiend.cpp
rename : src/scripts/outland/black_temple/boss_warlord_najentus.cpp => src/server/scripts/outland/black_temple/boss_warlord_najentus.cpp
rename : src/scripts/outland/black_temple/illidari_council.cpp => src/server/scripts/outland/black_temple/illidari_council.cpp
rename : src/scripts/outland/black_temple/instance_black_temple.cpp => src/server/scripts/outland/black_temple/instance_black_temple.cpp
rename : src/scripts/outland/blades_edge_mountains.cpp => src/server/scripts/outland/blades_edge_mountains.cpp
rename : src/scripts/outland/boss_doomlord_kazzak.cpp => src/server/scripts/outland/boss_doomlord_kazzak.cpp
rename : src/scripts/outland/boss_doomwalker.cpp => src/server/scripts/outland/boss_doomwalker.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp
rename : src/scripts/outland/coilfang_resevoir/serpent_shrine/serpent_shrine.h => src/server/scripts/outland/coilfang_resevoir/serpent_shrine/serpent_shrine.h
rename : src/scripts/outland/coilfang_resevoir/steam_vault/boss_hydromancer_thespia.cpp => src/server/scripts/outland/coilfang_resevoir/steam_vault/boss_hydromancer_thespia.cpp
rename : src/scripts/outland/coilfang_resevoir/steam_vault/boss_mekgineer_steamrigger.cpp => src/server/scripts/outland/coilfang_resevoir/steam_vault/boss_mekgineer_steamrigger.cpp
rename : src/scripts/outland/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp => src/server/scripts/outland/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp
rename : src/scripts/outland/coilfang_resevoir/steam_vault/instance_steam_vault.cpp => src/server/scripts/outland/coilfang_resevoir/steam_vault/instance_steam_vault.cpp
rename : src/scripts/outland/coilfang_resevoir/steam_vault/steam_vault.h => src/server/scripts/outland/coilfang_resevoir/steam_vault/steam_vault.h
rename : src/scripts/outland/coilfang_resevoir/underbog/boss_hungarfen.cpp => src/server/scripts/outland/coilfang_resevoir/underbog/boss_hungarfen.cpp
rename : src/scripts/outland/coilfang_resevoir/underbog/boss_the_black_stalker.cpp => src/server/scripts/outland/coilfang_resevoir/underbog/boss_the_black_stalker.cpp
rename : src/scripts/outland/gruuls_lair/boss_gruul.cpp => src/server/scripts/outland/gruuls_lair/boss_gruul.cpp
rename : src/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp => src/server/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp
rename : src/scripts/outland/gruuls_lair/gruuls_lair.h => src/server/scripts/outland/gruuls_lair/gruuls_lair.h
rename : src/scripts/outland/gruuls_lair/instance_gruuls_lair.cpp => src/server/scripts/outland/gruuls_lair/instance_gruuls_lair.cpp
rename : src/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h => src/server/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h
rename : src/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp => src/server/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp
rename : src/scripts/outland/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp => src/server/scripts/outland/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp
rename : src/scripts/outland/hellfire_citadel/blood_furnace/boss_the_maker.cpp => src/server/scripts/outland/hellfire_citadel/blood_furnace/boss_the_maker.cpp
rename : src/scripts/outland/hellfire_citadel/blood_furnace/instance_blood_furnace.cpp => src/server/scripts/outland/hellfire_citadel/blood_furnace/instance_blood_furnace.cpp
rename : src/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp => src/server/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp
rename : src/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_vazruden_the_herald.cpp => src/server/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_vazruden_the_herald.cpp
rename : src/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp => src/server/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp
rename : src/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h => src/server/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h
rename : src/scripts/outland/hellfire_citadel/hellfire_ramparts/instance_hellfire_ramparts.cpp => src/server/scripts/outland/hellfire_citadel/hellfire_ramparts/instance_hellfire_ramparts.cpp
rename : src/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp => src/server/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp
rename : src/scripts/outland/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp => src/server/scripts/outland/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp
rename : src/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h => src/server/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h
rename : src/scripts/outland/hellfire_citadel/shattered_halls/boss_nethekurse.cpp => src/server/scripts/outland/hellfire_citadel/shattered_halls/boss_nethekurse.cpp
rename : src/scripts/outland/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp => src/server/scripts/outland/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp
rename : src/scripts/outland/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp => src/server/scripts/outland/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp
rename : src/scripts/outland/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp => src/server/scripts/outland/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp
rename : src/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h => src/server/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h
rename : src/scripts/outland/hellfire_peninsula.cpp => src/server/scripts/outland/hellfire_peninsula.cpp
rename : src/scripts/outland/nagrand.cpp => src/server/scripts/outland/nagrand.cpp
rename : src/scripts/outland/netherstorm.cpp => src/server/scripts/outland/netherstorm.cpp
rename : src/scripts/outland/shadowmoon_valley.cpp => src/server/scripts/outland/shadowmoon_valley.cpp
rename : src/scripts/outland/shattrath_city.cpp => src/server/scripts/outland/shattrath_city.cpp
rename : src/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp => src/server/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp
rename : src/scripts/outland/tempest_keep/arcatraz/arcatraz.h => src/server/scripts/outland/tempest_keep/arcatraz/arcatraz.h
rename : src/scripts/outland/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp => src/server/scripts/outland/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp
rename : src/scripts/outland/tempest_keep/arcatraz/instance_arcatraz.cpp => src/server/scripts/outland/tempest_keep/arcatraz/instance_arcatraz.cpp
rename : src/scripts/outland/tempest_keep/botanica/boss_high_botanist_freywinn.cpp => src/server/scripts/outland/tempest_keep/botanica/boss_high_botanist_freywinn.cpp
rename : src/scripts/outland/tempest_keep/botanica/boss_laj.cpp => src/server/scripts/outland/tempest_keep/botanica/boss_laj.cpp
rename : src/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp => src/server/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp
rename : src/scripts/outland/tempest_keep/the_eye/boss_alar.cpp => src/server/scripts/outland/tempest_keep/the_eye/boss_alar.cpp
rename : src/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp => src/server/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp
rename : src/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp => src/server/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp
rename : src/scripts/outland/tempest_keep/the_eye/boss_void_reaver.cpp => src/server/scripts/outland/tempest_keep/the_eye/boss_void_reaver.cpp
rename : src/scripts/outland/tempest_keep/the_eye/instance_the_eye.cpp => src/server/scripts/outland/tempest_keep/the_eye/instance_the_eye.cpp
rename : src/scripts/outland/tempest_keep/the_eye/the_eye.cpp => src/server/scripts/outland/tempest_keep/the_eye/the_eye.cpp
rename : src/scripts/outland/tempest_keep/the_eye/the_eye.h => src/server/scripts/outland/tempest_keep/the_eye/the_eye.h
rename : src/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp => src/server/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_gyrokill.cpp
rename : src/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp => src/server/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp
rename : src/scripts/outland/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp => src/server/scripts/outland/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp
rename : src/scripts/outland/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp => src/server/scripts/outland/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp
rename : src/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp => src/server/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp
rename : src/scripts/outland/tempest_keep/the_mechanar/mechanar.h => src/server/scripts/outland/tempest_keep/the_mechanar/mechanar.h
rename : src/scripts/outland/terokkar_forest.cpp => src/server/scripts/outland/terokkar_forest.cpp
rename : src/scripts/outland/zangarmarsh.cpp => src/server/scripts/outland/zangarmarsh.cpp
rename : src/scripts/world/areatrigger_scripts.cpp => src/server/scripts/world/areatrigger_scripts.cpp
rename : src/scripts/world/boss_emeriss.cpp => src/server/scripts/world/boss_emeriss.cpp
rename : src/scripts/world/boss_lethon.cpp => src/server/scripts/world/boss_lethon.cpp
rename : src/scripts/world/boss_taerar.cpp => src/server/scripts/world/boss_taerar.cpp
rename : src/scripts/world/boss_ysondre.cpp => src/server/scripts/world/boss_ysondre.cpp
rename : src/scripts/world/go_scripts.cpp => src/server/scripts/world/go_scripts.cpp
rename : src/scripts/world/guards.cpp => src/server/scripts/world/guards.cpp
rename : src/scripts/world/item_scripts.cpp => src/server/scripts/world/item_scripts.cpp
rename : src/scripts/world/mob_generic_creature.cpp => src/server/scripts/world/mob_generic_creature.cpp
rename : src/scripts/world/npc_innkeeper.cpp => src/server/scripts/world/npc_innkeeper.cpp
rename : src/scripts/world/npc_professions.cpp => src/server/scripts/world/npc_professions.cpp
rename : src/scripts/world/npc_taxi.cpp => src/server/scripts/world/npc_taxi.cpp
rename : src/scripts/world/npcs_special.cpp => src/server/scripts/world/npcs_special.cpp
rename : src/shared/Auth/AuthCrypt.cpp => src/server/shared/Auth/AuthCrypt.cpp
rename : src/shared/Auth/AuthCrypt.h => src/server/shared/Auth/AuthCrypt.h
rename : src/shared/Auth/BigNumber.cpp => src/server/shared/Auth/BigNumber.cpp
rename : src/shared/Auth/BigNumber.h => src/server/shared/Auth/BigNumber.h
rename : src/shared/Auth/CMakeLists.txt => src/server/shared/Auth/CMakeLists.txt
rename : src/shared/Auth/Hmac.cpp => src/server/shared/Auth/Hmac.cpp
rename : src/shared/Auth/Hmac.h => src/server/shared/Auth/Hmac.h
rename : src/shared/Auth/SARC4.cpp => src/server/shared/Auth/SARC4.cpp
rename : src/shared/Auth/SARC4.h => src/server/shared/Auth/SARC4.h
rename : src/shared/Auth/Sha1.cpp => src/server/shared/Auth/Sha1.cpp
rename : src/shared/Auth/Sha1.h => src/server/shared/Auth/Sha1.h
rename : src/shared/Auth/md5.c => src/server/shared/Auth/md5.c
rename : src/shared/Auth/md5.h => src/server/shared/Auth/md5.h
rename : src/shared/ByteBuffer.h => src/server/shared/ByteBuffer.h
rename : src/shared/CMakeLists.txt => src/server/shared/CMakeLists.txt
rename : src/shared/Common.cpp => src/server/shared/Common.cpp
rename : src/shared/Common.h => src/server/shared/Common.h
rename : src/shared/Config/CMakeLists.txt => src/server/shared/Config/CMakeLists.txt
rename : src/shared/Config/Config.cpp => src/server/shared/Config/Config.cpp
rename : src/shared/Config/Config.h => src/server/shared/Config/Config.h
rename : src/shared/Config/ConfigEnv.h => src/server/shared/Config/ConfigEnv.h
rename : src/shared/Config/ConfigLibrary.vcproj => src/server/shared/Config/ConfigLibrary.vcproj
rename : src/shared/Config/dotconfpp/dotconfpp.cpp => src/server/shared/Config/dotconfpp/dotconfpp.cpp
rename : src/shared/Config/dotconfpp/dotconfpp.h => src/server/shared/Config/dotconfpp/dotconfpp.h
rename : src/shared/Config/dotconfpp/mempool.cpp => src/server/shared/Config/dotconfpp/mempool.cpp
rename : src/shared/Config/dotconfpp/mempool.h => src/server/shared/Config/dotconfpp/mempool.h
rename : src/shared/Database/CMakeLists.txt => src/server/shared/Database/CMakeLists.txt
rename : src/shared/Database/DBCFileLoader.cpp => src/server/shared/Database/DBCFileLoader.cpp
rename : src/shared/Database/DBCFileLoader.h => src/server/shared/Database/DBCFileLoader.h
rename : src/shared/Database/DBCStore.h => src/server/shared/Database/DBCStore.h
rename : src/shared/Database/Database.cpp => src/server/shared/Database/Database.cpp
rename : src/shared/Database/Database.h => src/server/shared/Database/Database.h
rename : src/shared/Database/DatabaseEnv.h => src/server/shared/Database/DatabaseEnv.h
rename : src/shared/Database/DatabaseImpl.h => src/server/shared/Database/DatabaseImpl.h
rename : src/shared/Database/Field.cpp => src/server/shared/Database/Field.cpp
rename : src/shared/Database/Field.h => src/server/shared/Database/Field.h
rename : src/shared/Database/QueryResult.cpp => src/server/shared/Database/QueryResult.cpp
rename : src/shared/Database/QueryResult.h => src/server/shared/Database/QueryResult.h
rename : src/shared/Database/SQLStorage.cpp => src/server/shared/Database/SQLStorage.cpp
rename : src/shared/Database/SQLStorage.h => src/server/shared/Database/SQLStorage.h
rename : src/shared/Database/SQLStorageImpl.h => src/server/shared/Database/SQLStorageImpl.h
rename : src/shared/Database/SqlDelayThread.cpp => src/server/shared/Database/SqlDelayThread.cpp
rename : src/shared/Database/SqlDelayThread.h => src/server/shared/Database/SqlDelayThread.h
rename : src/shared/Database/SqlOperations.cpp => src/server/shared/Database/SqlOperations.cpp
rename : src/shared/Database/SqlOperations.h => src/server/shared/Database/SqlOperations.h
rename : src/shared/DelayExecutor.cpp => src/server/shared/DelayExecutor.cpp
rename : src/shared/DelayExecutor.h => src/server/shared/DelayExecutor.h
rename : src/shared/Errors.h => src/server/shared/Errors.h
rename : src/shared/LockedQueue.h => src/server/shared/LockedQueue.h
rename : src/shared/Log.cpp => src/server/shared/Log.cpp
rename : src/shared/Log.h => src/server/shared/Log.h
rename : src/shared/MemoryLeaks.cpp => src/server/shared/MemoryLeaks.cpp
rename : src/shared/MemoryLeaks.h => src/server/shared/MemoryLeaks.h
rename : src/shared/PacketLog.cpp => src/server/shared/PacketLog.cpp
rename : src/shared/PacketLog.h => src/server/shared/PacketLog.h
rename : src/shared/ProgressBar.cpp => src/server/shared/ProgressBar.cpp
rename : src/shared/ProgressBar.h => src/server/shared/ProgressBar.h
rename : src/shared/ServiceWin32.cpp => src/server/shared/ServiceWin32.cpp
rename : src/shared/ServiceWin32.h => src/server/shared/ServiceWin32.h
rename : src/shared/SignalHandler.h => src/server/shared/SignalHandler.h
rename : src/shared/SystemConfig.h => src/server/shared/SystemConfig.h
rename : src/shared/Threading.cpp => src/server/shared/Threading.cpp
rename : src/shared/Threading.h => src/server/shared/Threading.h
rename : src/shared/Timer.h => src/server/shared/Timer.h
rename : src/shared/Util.cpp => src/server/shared/Util.cpp
rename : src/shared/Util.h => src/server/shared/Util.h
rename : src/shared/WheatyExceptionReport.cpp => src/server/shared/WheatyExceptionReport.cpp
rename : src/shared/WheatyExceptionReport.h => src/server/shared/WheatyExceptionReport.h
rename : src/shared/WorldPacket.h => src/server/shared/WorldPacket.h
rename : src/shared/vmap/BIH.cpp => src/server/shared/vmap/BIH.cpp
rename : src/shared/vmap/BIH.h => src/server/shared/vmap/BIH.h
rename : src/shared/vmap/CMakeLists.txt => src/server/shared/vmap/CMakeLists.txt
rename : src/shared/vmap/IVMapManager.h => src/server/shared/vmap/IVMapManager.h
rename : src/shared/vmap/MapTree.cpp => src/server/shared/vmap/MapTree.cpp
rename : src/shared/vmap/MapTree.h => src/server/shared/vmap/MapTree.h
rename : src/shared/vmap/ModelInstance.cpp => src/server/shared/vmap/ModelInstance.cpp
rename : src/shared/vmap/ModelInstance.h => src/server/shared/vmap/ModelInstance.h
rename : src/shared/vmap/TileAssembler.cpp => src/server/shared/vmap/TileAssembler.cpp
rename : src/shared/vmap/TileAssembler.h => src/server/shared/vmap/TileAssembler.h
rename : src/shared/vmap/VMapDefinitions.h => src/server/shared/vmap/VMapDefinitions.h
rename : src/shared/vmap/VMapFactory.cpp => src/server/shared/vmap/VMapFactory.cpp
rename : src/shared/vmap/VMapFactory.h => src/server/shared/vmap/VMapFactory.h
rename : src/shared/vmap/VMapManager2.cpp => src/server/shared/vmap/VMapManager2.cpp
rename : src/shared/vmap/VMapManager2.h => src/server/shared/vmap/VMapManager2.h
rename : src/shared/vmap/VMapTools.h => src/server/shared/vmap/VMapTools.h
rename : src/shared/vmap/WorldModel.cpp => src/server/shared/vmap/WorldModel.cpp
rename : src/shared/vmap/WorldModel.h => src/server/shared/vmap/WorldModel.h
rename : src/trinitycore/CMakeLists.txt => src/server/trinitycore/CMakeLists.txt
rename : src/trinitycore/CliRunnable.cpp => src/server/trinitycore/CliRunnable.cpp
rename : src/trinitycore/CliRunnable.h => src/server/trinitycore/CliRunnable.h
rename : src/trinitycore/Main.cpp => src/server/trinitycore/Main.cpp
rename : src/trinitycore/Master.cpp => src/server/trinitycore/Master.cpp
rename : src/trinitycore/Master.h => src/server/trinitycore/Master.h
rename : src/trinitycore/RASocket.cpp => src/server/trinitycore/RASocket.cpp
rename : src/trinitycore/RASocket.h => src/server/trinitycore/RASocket.h
rename : src/trinitycore/TrinityCore.ico => src/server/trinitycore/TrinityCore.ico
rename : src/trinitycore/TrinityCore.rc => src/server/trinitycore/TrinityCore.rc
rename : src/trinitycore/WorldRunnable.cpp => src/server/trinitycore/WorldRunnable.cpp
rename : src/trinitycore/WorldRunnable.h => src/server/trinitycore/WorldRunnable.h
rename : src/trinitycore/resource.h => src/server/trinitycore/resource.h
rename : src/trinitycore/trinitycore.conf.dist => src/server/trinitycore/trinitycore.conf.dist
rename : src/trinityrealm/AuthCodes.cpp => src/server/trinityrealm/AuthCodes.cpp
rename : src/trinityrealm/AuthCodes.h => src/server/trinityrealm/AuthCodes.h
rename : src/trinityrealm/AuthSocket.cpp => src/server/trinityrealm/AuthSocket.cpp
rename : src/trinityrealm/AuthSocket.h => src/server/trinityrealm/AuthSocket.h
rename : src/trinityrealm/CMakeLists.txt => src/server/trinityrealm/CMakeLists.txt
rename : src/trinityrealm/Main.cpp => src/server/trinityrealm/Main.cpp
rename : src/trinityrealm/RealmAcceptor.h => src/server/trinityrealm/RealmAcceptor.h
rename : src/trinityrealm/RealmList.cpp => src/server/trinityrealm/RealmList.cpp
rename : src/trinityrealm/RealmList.h => src/server/trinityrealm/RealmList.h
rename : src/trinityrealm/RealmSocket.cpp => src/server/trinityrealm/RealmSocket.cpp
rename : src/trinityrealm/RealmSocket.h => src/server/trinityrealm/RealmSocket.h
rename : src/trinityrealm/TrinityRealm.ico => src/server/trinityrealm/TrinityRealm.ico
rename : src/trinityrealm/TrinityRealm.rc => src/server/trinityrealm/TrinityRealm.rc
rename : src/trinityrealm/resource.h => src/server/trinityrealm/resource.h
rename : src/trinityrealm/trinityrealm.conf.dist => src/server/trinityrealm/trinityrealm.conf.dist
Diffstat (limited to 'src/server/shared')
87 files changed, 15192 insertions, 0 deletions
diff --git a/src/server/shared/Auth/AuthCrypt.cpp b/src/server/shared/Auth/AuthCrypt.cpp new file mode 100644 index 00000000000..b34b922b16a --- /dev/null +++ b/src/server/shared/Auth/AuthCrypt.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AuthCrypt.h" +#include "Hmac.h" +#include "Log.h" +#include "BigNumber.h" + +AuthCrypt::AuthCrypt() : _clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH) +{ + _initialized = false; +} + +AuthCrypt::~AuthCrypt() +{ + +} + +void AuthCrypt::Init(BigNumber *K) +{ + uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; + HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); + uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); + + uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE }; + HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); + uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); + + //SARC4 _serverDecrypt(encryptHash); + _clientDecrypt.Init(decryptHash); + _serverEncrypt.Init(encryptHash); + //SARC4 _clientEncrypt(decryptHash); + + uint8 syncBuf[1024]; + + memset(syncBuf, 0, 1024); + + _serverEncrypt.UpdateData(1024, syncBuf); + //_clientEncrypt.UpdateData(1024, syncBuf); + + memset(syncBuf, 0, 1024); + + //_serverDecrypt.UpdateData(1024, syncBuf); + _clientDecrypt.UpdateData(1024, syncBuf); + + _initialized = true; +} + +void AuthCrypt::DecryptRecv(uint8 *data, size_t len) +{ + if (!_initialized) + return; + + _clientDecrypt.UpdateData(len, data); +} + +void AuthCrypt::EncryptSend(uint8 *data, size_t len) +{ + if (!_initialized) + return; + + _serverEncrypt.UpdateData(len, data); +} + diff --git a/src/server/shared/Auth/AuthCrypt.h b/src/server/shared/Auth/AuthCrypt.h new file mode 100644 index 00000000000..6695dc580cc --- /dev/null +++ b/src/server/shared/Auth/AuthCrypt.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AUTHCRYPT_H +#define _AUTHCRYPT_H + +#include <Common.h> +#include "SARC4.h" + +class BigNumber; + +class AuthCrypt +{ + public: + AuthCrypt(); + ~AuthCrypt(); + + void Init(BigNumber *K); + void DecryptRecv(uint8 *, size_t); + void EncryptSend(uint8 *, size_t); + + bool IsInitialized() { return _initialized; } + + private: + SARC4 _clientDecrypt; + SARC4 _serverEncrypt; + bool _initialized; +}; +#endif + diff --git a/src/server/shared/Auth/BigNumber.cpp b/src/server/shared/Auth/BigNumber.cpp new file mode 100644 index 00000000000..64e9ef21ccc --- /dev/null +++ b/src/server/shared/Auth/BigNumber.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Auth/BigNumber.h" +#include <openssl/bn.h> +#include <algorithm> + +BigNumber::BigNumber() +{ + _bn = BN_new(); + _array = NULL; +} + +BigNumber::BigNumber(const BigNumber &bn) +{ + _bn = BN_dup(bn._bn); + _array = NULL; +} + +BigNumber::BigNumber(uint32 val) +{ + _bn = BN_new(); + BN_set_word(_bn, val); + _array = NULL; +} + +BigNumber::~BigNumber() +{ + BN_free(_bn); + if(_array) delete[] _array; +} + +void BigNumber::SetDword(uint32 val) +{ + BN_set_word(_bn, val); +} + +void BigNumber::SetQword(uint64 val) +{ + BN_add_word(_bn, (uint32)(val >> 32)); + BN_lshift(_bn, _bn, 32); + BN_add_word(_bn, (uint32)(val & 0xFFFFFFFF)); +} + +void BigNumber::SetBinary(const uint8 *bytes, int len) +{ + uint8 t[1000]; + for (int i = 0; i < len; i++) t[i] = bytes[len - 1 - i]; + BN_bin2bn(t, len, _bn); +} + +void BigNumber::SetHexStr(const char *str) +{ + BN_hex2bn(&_bn, str); +} + +void BigNumber::SetRand(int numbits) +{ + BN_rand(_bn, numbits, 0, 1); +} + +BigNumber BigNumber::operator=(const BigNumber &bn) +{ + BN_copy(_bn, bn._bn); + return *this; +} + +BigNumber BigNumber::operator+=(const BigNumber &bn) +{ + BN_add(_bn, _bn, bn._bn); + return *this; +} + +BigNumber BigNumber::operator-=(const BigNumber &bn) +{ + BN_sub(_bn, _bn, bn._bn); + return *this; +} + +BigNumber BigNumber::operator*=(const BigNumber &bn) +{ + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_mul(_bn, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return *this; +} + +BigNumber BigNumber::operator/=(const BigNumber &bn) +{ + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_div(_bn, NULL, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return *this; +} + +BigNumber BigNumber::operator%=(const BigNumber &bn) +{ + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_mod(_bn, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return *this; +} + +BigNumber BigNumber::Exp(const BigNumber &bn) +{ + BigNumber ret; + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_exp(ret._bn, _bn, bn._bn, bnctx); + BN_CTX_free(bnctx); + + return ret; +} + +BigNumber BigNumber::ModExp(const BigNumber &bn1, const BigNumber &bn2) +{ + BigNumber ret; + BN_CTX *bnctx; + + bnctx = BN_CTX_new(); + BN_mod_exp(ret._bn, _bn, bn1._bn, bn2._bn, bnctx); + BN_CTX_free(bnctx); + + return ret; +} + +int BigNumber::GetNumBytes(void) +{ + return BN_num_bytes(_bn); +} + +uint32 BigNumber::AsDword() +{ + return (uint32)BN_get_word(_bn); +} + +bool BigNumber::isZero() const +{ + return BN_is_zero(_bn)!=0; +} + +uint8 *BigNumber::AsByteArray(int minSize, bool reverse) +{ + int length = (minSize >= GetNumBytes()) ? minSize : GetNumBytes(); + + if (_array) + { + delete[] _array; + _array = NULL; + } + _array = new uint8[length]; + + // If we need more bytes than length of BigNumber set the rest to 0 + if (length > GetNumBytes()) + memset((void*)_array, 0, length); + + BN_bn2bin(_bn, (unsigned char *)_array); + + if (reverse) + std::reverse(_array, _array + length); + + return _array; +} + +const char *BigNumber::AsHexStr() +{ + return BN_bn2hex(_bn); +} + +const char *BigNumber::AsDecStr() +{ + return BN_bn2dec(_bn); +} + diff --git a/src/server/shared/Auth/BigNumber.h b/src/server/shared/Auth/BigNumber.h new file mode 100644 index 00000000000..1dd43c83fc7 --- /dev/null +++ b/src/server/shared/Auth/BigNumber.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AUTH_BIGNUMBER_H +#define _AUTH_BIGNUMBER_H + +#include "Common.h" + +struct bignum_st; + +class BigNumber +{ + public: + BigNumber(); + BigNumber(const BigNumber &bn); + BigNumber(uint32); + ~BigNumber(); + + void SetDword(uint32); + void SetQword(uint64); + void SetBinary(const uint8 *bytes, int len); + void SetHexStr(const char *str); + + void SetRand(int numbits); + + BigNumber operator=(const BigNumber &bn); + + BigNumber operator+=(const BigNumber &bn); + BigNumber operator+(const BigNumber &bn) + { + BigNumber t(*this); + return t += bn; + } + BigNumber operator-=(const BigNumber &bn); + BigNumber operator-(const BigNumber &bn) + { + BigNumber t(*this); + return t -= bn; + } + BigNumber operator*=(const BigNumber &bn); + BigNumber operator*(const BigNumber &bn) + { + BigNumber t(*this); + return t *= bn; + } + BigNumber operator/=(const BigNumber &bn); + BigNumber operator/(const BigNumber &bn) + { + BigNumber t(*this); + return t /= bn; + } + BigNumber operator%=(const BigNumber &bn); + BigNumber operator%(const BigNumber &bn) + { + BigNumber t(*this); + return t %= bn; + } + + bool isZero() const; + + BigNumber ModExp(const BigNumber &bn1, const BigNumber &bn2); + BigNumber Exp(const BigNumber &); + + int GetNumBytes(void); + + struct bignum_st *BN() { return _bn; } + + uint32 AsDword(); + uint8* AsByteArray(int minSize = 0, bool reverse = true); + + const char *AsHexStr(); + const char *AsDecStr(); + + private: + struct bignum_st *_bn; + uint8 *_array; +}; +#endif + diff --git a/src/server/shared/Auth/CMakeLists.txt b/src/server/shared/Auth/CMakeLists.txt new file mode 100644 index 00000000000..c843a6b0f35 --- /dev/null +++ b/src/server/shared/Auth/CMakeLists.txt @@ -0,0 +1,27 @@ + +########### next target ############### + +SET(trinityauth_STAT_SRCS + AuthCrypt.cpp + AuthCrypt.h + BigNumber.cpp + BigNumber.h + Hmac.cpp + Hmac.h + Sha1.cpp + Sha1.h + md5.c + md5.h + SARC4.cpp + SARC4.h +) + +include_directories( + ${ACE_INCLUDE_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/src/shared + ${CMAKE_SOURCE_DIR}/src/framework + ${MYSQL_INCLUDE_DIR} +) + +add_library(trinityauth STATIC ${trinityauth_STAT_SRCS}) diff --git a/src/server/shared/Auth/Hmac.cpp b/src/server/shared/Auth/Hmac.cpp new file mode 100644 index 00000000000..a30f1b2d1e2 --- /dev/null +++ b/src/server/shared/Auth/Hmac.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Auth/Hmac.h" +#include "BigNumber.h" + +HmacHash::HmacHash(uint32 len, uint8 *seed) +{ + HMAC_CTX_init(&m_ctx); + HMAC_Init_ex(&m_ctx, seed, len, EVP_sha1(), NULL); +} + +HmacHash::~HmacHash() +{ + HMAC_CTX_cleanup(&m_ctx); +} + +void HmacHash::UpdateBigNumber(BigNumber *bn) +{ + UpdateData(bn->AsByteArray(), bn->GetNumBytes()); +} + +void HmacHash::UpdateData(const uint8 *data, int length) +{ + HMAC_Update(&m_ctx, data, length); +} + +void HmacHash::UpdateData(const std::string &str) +{ + UpdateData((uint8 const*)str.c_str(), str.length()); +} + +void HmacHash::Finalize() +{ + uint32 length = 0; + HMAC_Final(&m_ctx, (uint8*)m_digest, &length); + ASSERT(length == SHA_DIGEST_LENGTH) +} + +uint8 *HmacHash::ComputeHash(BigNumber *bn) +{ + HMAC_Update(&m_ctx, bn->AsByteArray(), bn->GetNumBytes()); + Finalize(); + return (uint8*)m_digest; +} diff --git a/src/server/shared/Auth/Hmac.h b/src/server/shared/Auth/Hmac.h new file mode 100644 index 00000000000..845d6e84802 --- /dev/null +++ b/src/server/shared/Auth/Hmac.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AUTH_HMAC_H +#define _AUTH_HMAC_H + +#include "Common.h" +#include <openssl/hmac.h> +#include <openssl/sha.h> + +class BigNumber; + +#define SEED_KEY_SIZE 16 + +class HmacHash +{ + public: + HmacHash(uint32 len, uint8 *seed); + ~HmacHash(); + void UpdateBigNumber(BigNumber *bn); + void UpdateData(const uint8 *data, int length); + void UpdateData(const std::string &str); + void Finalize(); + uint8 *ComputeHash(BigNumber *bn); + uint8 *GetDigest() { return (uint8*)m_digest; } + int GetLength() { return SHA_DIGEST_LENGTH; } + private: + HMAC_CTX m_ctx; + uint8 m_digest[SHA_DIGEST_LENGTH]; +}; +#endif + diff --git a/src/server/shared/Auth/SARC4.cpp b/src/server/shared/Auth/SARC4.cpp new file mode 100644 index 00000000000..80cad4991e9 --- /dev/null +++ b/src/server/shared/Auth/SARC4.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Auth/SARC4.h" +#include <openssl/sha.h> + +SARC4::SARC4(uint8 len) +{ + EVP_CIPHER_CTX_init(&m_ctx); + EVP_EncryptInit_ex(&m_ctx, EVP_rc4(), NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(&m_ctx, len); +} + +SARC4::SARC4(uint8 *seed, uint8 len) +{ + EVP_CIPHER_CTX_init(&m_ctx); + EVP_EncryptInit_ex(&m_ctx, EVP_rc4(), NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(&m_ctx, len); + EVP_EncryptInit_ex(&m_ctx, NULL, NULL, seed, NULL); +} + +SARC4::~SARC4() +{ + EVP_CIPHER_CTX_cleanup(&m_ctx); +} + +void SARC4::Init(uint8 *seed) +{ + EVP_EncryptInit_ex(&m_ctx, NULL, NULL, seed, NULL); +} + +void SARC4::UpdateData(int len, uint8 *data) +{ + int outlen = 0; + EVP_EncryptUpdate(&m_ctx, data, &outlen, data, len); + EVP_EncryptFinal_ex(&m_ctx, data, &outlen); +} diff --git a/src/server/shared/Auth/SARC4.h b/src/server/shared/Auth/SARC4.h new file mode 100644 index 00000000000..2e408627fc8 --- /dev/null +++ b/src/server/shared/Auth/SARC4.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AUTH_SARC4_H +#define _AUTH_SARC4_H + +#include "Common.h" +#include <openssl/evp.h> + +class SARC4 +{ + public: + SARC4(uint8 len); + SARC4(uint8 *seed, uint8 len); + ~SARC4(); + void Init(uint8 *seed); + void UpdateData(int len, uint8 *data); + private: + EVP_CIPHER_CTX m_ctx; +}; +#endif diff --git a/src/server/shared/Auth/Sha1.cpp b/src/server/shared/Auth/Sha1.cpp new file mode 100644 index 00000000000..b63deb2c5f3 --- /dev/null +++ b/src/server/shared/Auth/Sha1.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Auth/Sha1.h" +#include "Auth/BigNumber.h" +#include <stdarg.h> + +Sha1Hash::Sha1Hash() +{ + SHA1_Init(&mC); +} + +Sha1Hash::~Sha1Hash() +{ + SHA1_Init(&mC); +} + +void Sha1Hash::UpdateData(const uint8 *dta, int len) +{ + SHA1_Update(&mC, dta, len); +} + +void Sha1Hash::UpdateData(const std::string &str) +{ + UpdateData((uint8 const*)str.c_str(), str.length()); +} + +void Sha1Hash::UpdateBigNumbers(BigNumber *bn0, ...) +{ + va_list v; + BigNumber *bn; + + va_start(v, bn0); + bn = bn0; + while (bn) + { + UpdateData(bn->AsByteArray(), bn->GetNumBytes()); + bn = va_arg(v, BigNumber *); + } + va_end(v); +} + +void Sha1Hash::Initialize() +{ + SHA1_Init(&mC); +} + +void Sha1Hash::Finalize(void) +{ + SHA1_Final(mDigest, &mC); +} + diff --git a/src/server/shared/Auth/Sha1.h b/src/server/shared/Auth/Sha1.h new file mode 100644 index 00000000000..2d7f361ae9a --- /dev/null +++ b/src/server/shared/Auth/Sha1.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AUTH_SHA1_H +#define _AUTH_SHA1_H + +#include "Common.h" +#include <openssl/sha.h> +#include <openssl/crypto.h> + +class BigNumber; + +class Sha1Hash +{ + public: + Sha1Hash(); + ~Sha1Hash(); + + void UpdateFinalizeBigNumbers(BigNumber *bn0, ...); + void UpdateBigNumbers(BigNumber *bn0, ...); + + void UpdateData(const uint8 *dta, int len); + void UpdateData(const std::string &str); + + void Initialize(); + void Finalize(); + + uint8 *GetDigest(void) { return mDigest; }; + int GetLength(void) { return SHA_DIGEST_LENGTH; }; + + private: + SHA_CTX mC; + uint8 mDigest[SHA_DIGEST_LENGTH]; +}; +#endif + diff --git a/src/server/shared/Auth/md5.c b/src/server/shared/Auth/md5.c new file mode 100644 index 00000000000..3e9735e2dbb --- /dev/null +++ b/src/server/shared/Auth/md5.c @@ -0,0 +1,385 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +L. Peter Deutsch +ghost@aladdin.com + +*/ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + +The original and principal author of md5.c is L. Peter Deutsch +<ghost@aladdin.com>. Other authors are noted in the change history +that follows (in reverse chronological order): + +2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order +either statically or dynamically; added missing #include <string.h> +in library. +2002-03-11 lpd Corrected argument list for main(), and added int return +type, in test program and T value program. +2002-02-21 lpd Added missing #include <stdio.h> in test program. +2000-07-03 lpd Patched to eliminate warnings about "constant is +unsigned in ANSI C, signed in traditional"; made test program +self-checking. +1999-11-04 lpd Edited comments slightly for automatic TOC extraction. +1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). +1999-05-03 lpd Original version. +*/ + +#include "md5.h" +#include <string.h> + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + #if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; + #else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; + #endif + + { + #if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ + #endif + #if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) + { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } + else + { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } + #endif + #if BYTE_ORDER == 0 + else /* dynamic big-endian */ + #endif + #if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + + # if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ + # else + # define xbuf X /* (static only) */ + # endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } + #endif + } + + #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ + #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); + #undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ + #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); + #undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ + #define H(x, y, z) ((x) ^ (y) ^ (z)) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); + #undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ + #define I(x, y, z) ((y) ^ ((x) | ~(z))) + #define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); + #undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + ++pms->count[1]; + + /* Process an initial partial block. */ + if (offset) + { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/src/server/shared/Auth/md5.h b/src/server/shared/Auth/md5.h new file mode 100644 index 00000000000..0463051b6a6 --- /dev/null +++ b/src/server/shared/Auth/md5.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +L. Peter Deutsch +ghost@aladdin.com + +*/ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + +The original and principal author of md5.h is L. Peter Deutsch +<ghost@aladdin.com>. Other authors are noted in the change history +that follows (in reverse chronological order): + +2002-04-13 lpd Removed support for non-ANSI compilers; removed +references to Ghostscript; clarified derivation from RFC 1321; +now handles byte order either statically or dynamically. +1999-11-04 lpd Edited comments slightly for automatic TOC extraction. +1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); +added conditionalization for C++ compilation from Martin +Purschke <purschke@bnl.gov>. +1999-05-03 lpd Original version. +*/ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s +{ + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ + #endif + + /* Initialize the algorithm. */ + void md5_init(md5_state_t *pms); + + /* Append a string to the message. */ + void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + + /* Finish the message and return the digest. */ + void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + + #ifdef __cplusplus +} /* end extern "C" */ +#endif +#endif /* md5_INCLUDED */ + diff --git a/src/server/shared/ByteBuffer.h b/src/server/shared/ByteBuffer.h new file mode 100644 index 00000000000..ba0240fb58b --- /dev/null +++ b/src/server/shared/ByteBuffer.h @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _BYTEBUFFER_H +#define _BYTEBUFFER_H + +#include "Common.h" +#include "Errors.h" +#include "Log.h" +#include "Utilities/ByteConverter.h" + +class ByteBufferException +{ + public: + ByteBufferException(bool _add, size_t _pos, size_t _esize, size_t _size) + : add(_add), pos(_pos), esize(_esize), size(_size) + { + PrintPosError(); + } + + void PrintPosError() const + { + sLog.outError("ERROR: Attempted to %s in ByteBuffer (pos: " SIZEFMTD " size: "SIZEFMTD") value with size: " SIZEFMTD, + (add ? "put" : "get"), pos, size, esize); + } + private: + bool add; + size_t pos; + size_t esize; + size_t size; +}; + +class ByteBuffer +{ + public: + const static size_t DEFAULT_SIZE = 0x1000; + + // constructor + ByteBuffer(): _rpos(0), _wpos(0) + { + _storage.reserve(DEFAULT_SIZE); + } + + // constructor + ByteBuffer(size_t res): _rpos(0), _wpos(0) + { + _storage.reserve(res); + } + + // copy constructor + ByteBuffer(const ByteBuffer &buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage) { } + + void clear() + { + _storage.clear(); + _rpos = _wpos = 0; + } + + template <typename T> void append(T value) + { + EndianConvert(value); + append((uint8 *)&value, sizeof(value)); + } + + template <typename T> void put(size_t pos,T value) + { + EndianConvert(value); + put(pos,(uint8 *)&value,sizeof(value)); + } + + ByteBuffer &operator<<(uint8 value) + { + append<uint8>(value); + return *this; + } + + ByteBuffer &operator<<(uint16 value) + { + append<uint16>(value); + return *this; + } + + ByteBuffer &operator<<(uint32 value) + { + append<uint32>(value); + return *this; + } + + ByteBuffer &operator<<(uint64 value) + { + append<uint64>(value); + return *this; + } + + // signed as in 2e complement + ByteBuffer &operator<<(int8 value) + { + append<int8>(value); + return *this; + } + + ByteBuffer &operator<<(int16 value) + { + append<int16>(value); + return *this; + } + + ByteBuffer &operator<<(int32 value) + { + append<int32>(value); + return *this; + } + + ByteBuffer &operator<<(int64 value) + { + append<int64>(value); + return *this; + } + + // floating points + ByteBuffer &operator<<(float value) + { + append<float>(value); + return *this; + } + + ByteBuffer &operator<<(double value) + { + append<double>(value); + return *this; + } + + ByteBuffer &operator<<(const std::string &value) + { + append((uint8 const *)value.c_str(), value.length()); + append((uint8)0); + return *this; + } + + ByteBuffer &operator<<(const char *str) + { + append((uint8 const *)str, str ? strlen(str) : 0); + append((uint8)0); + return *this; + } + + ByteBuffer &operator>>(bool &value) + { + value = read<char>() > 0 ? true : false; + return *this; + } + + ByteBuffer &operator>>(uint8 &value) + { + value = read<uint8>(); + return *this; + } + + ByteBuffer &operator>>(uint16 &value) + { + value = read<uint16>(); + return *this; + } + + ByteBuffer &operator>>(uint32 &value) + { + value = read<uint32>(); + return *this; + } + + ByteBuffer &operator>>(uint64 &value) + { + value = read<uint64>(); + return *this; + } + + //signed as in 2e complement + ByteBuffer &operator>>(int8 &value) + { + value = read<int8>(); + return *this; + } + + ByteBuffer &operator>>(int16 &value) + { + value = read<int16>(); + return *this; + } + + ByteBuffer &operator>>(int32 &value) + { + value = read<int32>(); + return *this; + } + + ByteBuffer &operator>>(int64 &value) + { + value = read<int64>(); + return *this; + } + + ByteBuffer &operator>>(float &value) + { + value = read<float>(); + return *this; + } + + ByteBuffer &operator>>(double &value) + { + value = read<double>(); + return *this; + } + + ByteBuffer &operator>>(std::string& value) + { + value.clear(); + while (rpos() < size()) // prevent crash at wrong string format in packet + { + char c = read<char>(); + if (c == 0) + break; + value += c; + } + return *this; + } + + uint8 operator[](size_t pos) const + { + return read<uint8>(pos); + } + + size_t rpos() const { return _rpos; } + + size_t rpos(size_t rpos_) + { + _rpos = rpos_; + return _rpos; + } + + size_t wpos() const { return _wpos; } + + size_t wpos(size_t wpos_) + { + _wpos = wpos_; + return _wpos; + } + + template<typename T> + void read_skip() { read_skip(sizeof(T)); } + + void read_skip(size_t skip) + { + if(_rpos + skip > size()) + throw ByteBufferException(false, _rpos, skip, size()); + _rpos += skip; + } + + template <typename T> T read() + { + T r = read<T>(_rpos); + _rpos += sizeof(T); + return r; + } + + template <typename T> T read(size_t pos) const + { + if(pos + sizeof(T) > size()) + throw ByteBufferException(false, pos, sizeof(T), size()); + T val = *((T const*)&_storage[pos]); + EndianConvert(val); + return val; + } + + void read(uint8 *dest, size_t len) + { + if(_rpos + len > size()) + throw ByteBufferException(false, _rpos, len, size()); + memcpy(dest, &_storage[_rpos], len); + _rpos += len; + } + + bool readPackGUID(uint64& guid) + { + if(rpos() + 1 > size()) + return false; + + guid = 0; + + uint8 guidmark = 0; + (*this) >> guidmark; + + for (int i = 0; i < 8; ++i) + { + if(guidmark & (uint8(1) << i)) + { + if(rpos() + 1 > size()) + return false; + + uint8 bit; + (*this) >> bit; + guid |= (uint64(bit) << (i * 8)); + } + } + + return true; + } + + const uint8 *contents() const { return &_storage[0]; } + + size_t size() const { return _storage.size(); } + bool empty() const { return _storage.empty(); } + + void resize(size_t newsize) + { + _storage.resize(newsize); + _rpos = 0; + _wpos = size(); + } + + void reserve(size_t ressize) + { + if (ressize > size()) + _storage.reserve(ressize); + } + + void append(const std::string& str) + { + append((uint8 const*)str.c_str(), str.size() + 1); + } + + void append(const char *src, size_t cnt) + { + return append((const uint8 *)src, cnt); + } + + template<class T> void append(const T *src, size_t cnt) + { + return append((const uint8 *)src, cnt * sizeof(T)); + } + + void append(const uint8 *src, size_t cnt) + { + if (!cnt) + return; + + ASSERT(size() < 10000000); + + if (_storage.size() < _wpos + cnt) + _storage.resize(_wpos + cnt); + memcpy(&_storage[_wpos], src, cnt); + _wpos += cnt; + } + + void append(const ByteBuffer& buffer) + { + if(buffer.wpos()) + append(buffer.contents(), buffer.wpos()); + } + + // can be used in SMSG_MONSTER_MOVE opcode + void appendPackXYZ(float x, float y, float z) + { + uint32 packed = 0; + packed |= ((int)(x / 0.25f) & 0x7FF); + packed |= ((int)(y / 0.25f) & 0x7FF) << 11; + packed |= ((int)(z / 0.25f) & 0x3FF) << 22; + *this << packed; + } + + void appendPackGUID(uint64 guid) + { + uint8 packGUID[8+1]; + packGUID[0] = 0; + size_t size = 1; + for(uint8 i = 0;guid != 0;++i) + { + if(guid & 0xFF) + { + packGUID[0] |= uint8(1 << i); + packGUID[size] = uint8(guid & 0xFF); + ++size; + } + + guid >>= 8; + } + append(packGUID, size); + } + + void put(size_t pos, const uint8 *src, size_t cnt) + { + if(pos + cnt > size()) + throw ByteBufferException(true, pos, cnt, size()); + memcpy(&_storage[pos], src, cnt); + } + + void print_storage() const + { + if(!sLog.IsOutDebug()) // optimize disabled debug output + return; + + sLog.outDebug("STORAGE_SIZE: %lu", (unsigned long)size() ); + for (uint32 i = 0; i < size(); ++i) + sLog.outDebugInLine("%u - ", read<uint8>(i) ); + sLog.outDebug(" "); + } + + void textlike() const + { + if(!sLog.IsOutDebug()) // optimize disabled debug output + return; + + sLog.outDebug("STORAGE_SIZE: %lu", (unsigned long)size() ); + for (uint32 i = 0; i < size(); ++i) + sLog.outDebugInLine("%c", read<uint8>(i) ); + sLog.outDebug(" "); + } + + void hexlike() const + { + if(!sLog.IsOutDebug()) // optimize disabled debug output + return; + + uint32 j = 1, k = 1; + sLog.outDebug("STORAGE_SIZE: %lu", (unsigned long)size() ); + + for (uint32 i = 0; i < size(); ++i) + { + if ((i == (j * 8)) && ((i != (k * 16)))) + { + if (read<uint8>(i) < 0x10) + { + sLog.outDebugInLine("| 0%X ", read<uint8>(i) ); + } + else + { + sLog.outDebugInLine("| %X ", read<uint8>(i) ); + } + ++j; + } + else if (i == (k * 16)) + { + if (read<uint8>(i) < 0x10) + { + sLog.outDebugInLine("\n"); + + sLog.outDebugInLine("0%X ", read<uint8>(i) ); + } + else + { + sLog.outDebugInLine("\n"); + + sLog.outDebugInLine("%X ", read<uint8>(i) ); + } + + ++k; + ++j; + } + else + { + if (read<uint8>(i) < 0x10) + { + sLog.outDebugInLine("0%X ", read<uint8>(i) ); + } + else + { + sLog.outDebugInLine("%X ", read<uint8>(i) ); + } + } + } + sLog.outDebugInLine("\n"); + } + + protected: + size_t _rpos, _wpos; + std::vector<uint8> _storage; +}; + +template <typename T> +inline ByteBuffer &operator<<(ByteBuffer &b, std::vector<T> v) +{ + b << (uint32)v.size(); + for (typename std::vector<T>::iterator i = v.begin(); i != v.end(); ++i) + { + b << *i; + } + return b; +} + +template <typename T> +inline ByteBuffer &operator>>(ByteBuffer &b, std::vector<T> &v) +{ + uint32 vsize; + b >> vsize; + v.clear(); + while(vsize--) + { + T t; + b >> t; + v.push_back(t); + } + return b; +} + +template <typename T> +inline ByteBuffer &operator<<(ByteBuffer &b, std::list<T> v) +{ + b << (uint32)v.size(); + for (typename std::list<T>::iterator i = v.begin(); i != v.end(); ++i) + { + b << *i; + } + return b; +} + +template <typename T> +inline ByteBuffer &operator>>(ByteBuffer &b, std::list<T> &v) +{ + uint32 vsize; + b >> vsize; + v.clear(); + while(vsize--) + { + T t; + b >> t; + v.push_back(t); + } + return b; +} + +template <typename K, typename V> +inline ByteBuffer &operator<<(ByteBuffer &b, std::map<K, V> &m) +{ + b << (uint32)m.size(); + for (typename std::map<K, V>::iterator i = m.begin(); i != m.end(); ++i) + { + b << i->first << i->second; + } + return b; +} + +template <typename K, typename V> +inline ByteBuffer &operator>>(ByteBuffer &b, std::map<K, V> &m) +{ + uint32 msize; + b >> msize; + m.clear(); + while(msize--) + { + K k; + V v; + b >> k >> v; + m.insert(make_pair(k, v)); + } + return b; +} + +// TODO: Make a ByteBuffer.cpp and move all this inlining to it. +template<> inline std::string ByteBuffer::read<std::string>() +{ + std::string tmp; + *this >> tmp; + return tmp; +} + +template<> +inline void ByteBuffer::read_skip<char*>() +{ + std::string temp; + *this >> temp; +} + +template<> +inline void ByteBuffer::read_skip<char const*>() +{ + read_skip<char*>(); +} + +template<> +inline void ByteBuffer::read_skip<std::string>() +{ + read_skip<char*>(); +} +#endif + diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt new file mode 100644 index 00000000000..d00f8b83fb8 --- /dev/null +++ b/src/server/shared/CMakeLists.txt @@ -0,0 +1,42 @@ +add_subdirectory(vmap) +add_subdirectory(Auth) +add_subdirectory(Config) +add_subdirectory(Database) + +########### next target ############### + +SET(shared_STAT_SRCS + ByteBuffer.h + Common.cpp + Common.h + DelayExecutor.cpp + DelayExecutor.h + Errors.h + Log.cpp + Log.h + ProgressBar.cpp + ProgressBar.h + SignalHandler.h + Threading.cpp + Timer.h + Util.cpp + Util.h + WorldPacket.h + SystemConfig.h +) + +include_directories( + ${ACE_INCLUDE_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/include + ${CMAKE_SOURCE_DIR}/dep/include/sockets + ${CMAKE_SOURCE_DIR}/src/framework + ${CMAKE_SOURCE_DIR}/src/shared + ${MYSQL_INCLUDE_DIR} +) + +add_library(shared STATIC ${shared_STAT_SRCS}) +target_link_libraries( +shared +${ACE_LIBRARY} +) diff --git a/src/server/shared/Common.cpp b/src/server/shared/Common.cpp new file mode 100644 index 00000000000..49a45d67131 --- /dev/null +++ b/src/server/shared/Common.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" + +char const* localeNames[MAX_LOCALE] = { + "enUS", + "koKR", + "frFR", + "deDE", + "zhCN", + "zhTW", + "esES", + "esMX", + "ruRU" +}; + +LocaleConstant GetLocaleByName(const std::string& name) +{ + for (uint32 i = 0; i < MAX_LOCALE; ++i) + if(name==localeNames[i]) + return LocaleConstant(i); + + return LOCALE_enUS; // including enGB case +} + diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h new file mode 100644 index 00000000000..4a6aac43390 --- /dev/null +++ b/src/server/shared/Common.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_COMMON_H +#define TRINITYCORE_COMMON_H + +// config.h needs to be included 1st +// TODO this thingy looks like hack ,but its not, need to +// make separate header however, because It makes mess here. +#ifdef HAVE_CONFIG_H +// Remove Some things that we will define +// This is in case including another config.h +// before trinity config.h +#ifdef PACKAGE +#undef PACKAGE +#endif //PACKAGE +#ifdef PACKAGE_BUGREPORT +#undef PACKAGE_BUGREPORT +#endif //PACKAGE_BUGREPORT +#ifdef PACKAGE_NAME +#undef PACKAGE_NAME +#endif //PACKAGE_NAME +#ifdef PACKAGE_STRING +#undef PACKAGE_STRING +#endif //PACKAGE_STRING +#ifdef PACKAGE_TARNAME +#undef PACKAGE_TARNAME +#endif //PACKAGE_TARNAME +#ifdef PACKAGE_VERSION +#undef PACKAGE_VERSION +#endif //PACKAGE_VERSION +#ifdef VERSION +#undef VERSION +#endif //VERSION +# include "config.h" +#undef PACKAGE +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION +#undef VERSION +#endif //HAVE_CONFIG_H + +#include "Platform/Define.h" + +#if COMPILER == COMPILER_MICROSOFT +# pragma warning(disable:4996) // 'function': was declared deprecated +#ifndef __SHOW_STUPID_WARNINGS__ +# pragma warning(disable:4005) // 'identifier' : macro redefinition +# pragma warning(disable:4018) // 'expression' : signed/unsigned mismatch +# pragma warning(disable:4244) // 'argument' : conversion from 'type1' to 'type2', possible loss of data +# pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data +# pragma warning(disable:4305) // 'identifier' : truncation from 'type1' to 'type2' +# pragma warning(disable:4311) // 'variable' : pointer truncation from 'type' to 'type' +# pragma warning(disable:4355) // 'this' : used in base member initializer list +# pragma warning(disable:4800) // 'type' : forcing value to bool 'true' or 'false' (performance warning) +# pragma warning(disable:4522) //warning when class has 2 constructors +#endif // __SHOW_STUPID_WARNINGS__ +#endif // __GNUC__ + +#include "Utilities/UnorderedMap.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <math.h> +#include <errno.h> +#include <signal.h> +#include <assert.h> + +#if PLATFORM == PLATFORM_WINDOWS +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +#include <set> +#include <list> +#include <string> +#include <map> +#include <queue> +#include <sstream> +#include <algorithm> + +#include "LockedQueue.h" +#include "Threading.h" + +#include <ace/Basic_Types.h> +#include <ace/Guard_T.h> +#include <ace/RW_Thread_Mutex.h> +#include <ace/Thread_Mutex.h> + +#if PLATFORM == PLATFORM_WINDOWS +# define FD_SETSIZE 4096 +# include <ace/config-all.h> +// XP winver - needed to compile with standard leak check in MemoryLeaks.h +// uncomment later if needed +//#define _WIN32_WINNT 0x0501 +# include <ws2tcpip.h> +//#undef WIN32_WINNT +#else +# include <sys/types.h> +# include <sys/ioctl.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <unistd.h> +# include <netdb.h> +#endif + +#if COMPILER == COMPILER_MICROSOFT + +#include <float.h> + +#define I32FMT "%08I32X" +#define I64FMT "%016I64X" +#define snprintf _snprintf +#define atoll __atoi64 +#define vsnprintf _vsnprintf +#define strdup _strdup +#define finite(X) _finite(X) + +#else + +#define stricmp strcasecmp +#define strnicmp strncasecmp +#define I32FMT "%08X" +#define I64FMT "%016llX" + +#endif + +#define UI64FMTD ACE_UINT64_FORMAT_SPECIFIER +#define UI64LIT(N) ACE_UINT64_LITERAL(N) + +#define SI64FMTD ACE_INT64_FORMAT_SPECIFIER +#define SI64LIT(N) ACE_INT64_LITERAL(N) + +#define SIZEFMTD ACE_SIZE_T_FORMAT_SPECIFIER + +inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; } + +#define atol(a) strtoul( a, NULL, 10) + +#define STRINGIZE(a) #a + +enum TimeConstants +{ + MINUTE = 60, + HOUR = MINUTE*60, + DAY = HOUR*24, + WEEK = DAY*7, + MONTH = DAY*30, + YEAR = MONTH*12, + IN_MILISECONDS = 1000 +}; + +enum AccountTypes +{ + SEC_PLAYER = 0, + SEC_MODERATOR = 1, + SEC_GAMEMASTER = 2, + SEC_ADMINISTRATOR = 3, + SEC_CONSOLE = 4 // must be always last in list, accounts must have less security level always also +}; + +enum LocaleConstant +{ + LOCALE_enUS = 0, + LOCALE_koKR = 1, + LOCALE_frFR = 2, + LOCALE_deDE = 3, + LOCALE_zhCN = 4, + LOCALE_zhTW = 5, + LOCALE_esES = 6, + LOCALE_esMX = 7, + LOCALE_ruRU = 8 +}; + +const uint8 MAX_LOCALE = 9; + +extern char const* localeNames[MAX_LOCALE]; + +LocaleConstant GetLocaleByName(const std::string& name); + +// we always use stdlibc++ std::max/std::min, undefine some not C++ standard defines (Win API and some other platforms) +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#endif + diff --git a/src/server/shared/Config/CMakeLists.txt b/src/server/shared/Config/CMakeLists.txt new file mode 100644 index 00000000000..98065034f08 --- /dev/null +++ b/src/server/shared/Config/CMakeLists.txt @@ -0,0 +1,22 @@ + +########### next target ############### + +SET(trinityconfig_STAT_SRCS + dotconfpp/dotconfpp.cpp + dotconfpp/dotconfpp.h + dotconfpp/mempool.cpp + dotconfpp/mempool.h + Config.cpp + Config.h + ConfigEnv.h +) + +include_directories( + ${ACE_INCLUDE_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/src/shared + ${CMAKE_SOURCE_DIR}/src/framework +) + +add_library(trinityconfig STATIC ${trinityconfig_STAT_SRCS}) + diff --git a/src/server/shared/Config/Config.cpp b/src/server/shared/Config/Config.cpp new file mode 100644 index 00000000000..39830104a7c --- /dev/null +++ b/src/server/shared/Config/Config.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ConfigEnv.h" +#include "Policies/SingletonImp.h" + +INSTANTIATE_SINGLETON_1(Config); + +Config::Config() : mIgnoreCase(true), mConf(NULL) +{ +} + +Config::~Config() +{ + delete mConf; +} + +bool Config::SetSource(const char *file, bool ignorecase) +{ + mIgnoreCase = ignorecase; + mFilename = file; + + return Reload(); +} + +bool Config::Reload() +{ + delete mConf; + + mConf = new DOTCONFDocument(mIgnoreCase ? + DOTCONFDocument::CASEINSENSETIVE : + DOTCONFDocument::CASESENSETIVE); + + if (mConf->setContent(mFilename.c_str()) == -1) + { + delete mConf; + mConf = NULL; + return false; + } + + return true; +} + +std::string Config::GetStringDefault(const char * name, std::string def) +{ + if(!mConf) + return std::string(def); + const DOTCONFDocumentNode * node = mConf->findNode(name); + if(!node || !node->getValue()) + return std::string(def); + return std::string(node->getValue()); +}; + +bool Config::GetBoolDefault(const char * name, const bool def) +{ + if(!mConf) + return false; + const DOTCONFDocumentNode * node = mConf->findNode(name); + if(!node || !node->getValue()) + return def; + const char * str = node->getValue(); + if(strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0 || + strcmp(str, "yes") == 0 || strcmp(str, "YES") == 0 || + strcmp(str, "1") == 0) + return true; + else + return false; +}; + +int32 Config::GetIntDefault(const char * name, const int32 def) +{ + if(!mConf) + return def; + const DOTCONFDocumentNode * node = mConf->findNode(name); + if(!node || !node->getValue()) + return def; + return atoi(node->getValue()); +}; + +float Config::GetFloatDefault(const char * name, const float def) +{ + if(!mConf) + return def; + const DOTCONFDocumentNode * node = mConf->findNode(name); + if(!node || !node->getValue()) + return def; + return atof(node->getValue()); +}; diff --git a/src/server/shared/Config/Config.h b/src/server/shared/Config/Config.h new file mode 100644 index 00000000000..ccc76073e46 --- /dev/null +++ b/src/server/shared/Config/Config.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include <Policies/Singleton.h> +#include "Platform/Define.h" + +class DOTCONFDocument; + +class Config +{ + public: + Config(); + ~Config(); + + bool SetSource(const char *file, bool ignorecase = true); + bool Reload(); + + std::string GetStringDefault(const char * name, std::string def); + bool GetBoolDefault(const char * name, const bool def); + int32 GetIntDefault(const char * name, const int32 def); + float GetFloatDefault(const char * name, const float def); + + std::string GetFilename() const { return mFilename; } + private: + std::string mFilename; + bool mIgnoreCase; + DOTCONFDocument *mConf; +}; + +#define sConfig Trinity::Singleton<Config>::Instance() + +#endif + diff --git a/src/server/shared/Config/ConfigEnv.h b/src/server/shared/Config/ConfigEnv.h new file mode 100644 index 00000000000..16e596fd2da --- /dev/null +++ b/src/server/shared/Config/ConfigEnv.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(CONFIGENVIRONMENT_H) + +#define CONFIGENVIRONMENT_H + +#include "Common.h" +#include "dotconfpp/dotconfpp.h" +#include "Config.h" + +#endif + diff --git a/src/server/shared/Config/ConfigLibrary.vcproj b/src/server/shared/Config/ConfigLibrary.vcproj new file mode 100644 index 00000000000..a8f1fc322e7 --- /dev/null +++ b/src/server/shared/Config/ConfigLibrary.vcproj @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="ConfigLibrary" + ProjectGUID="{C849D54F-32A6-4025-95BE-E64D1CF0686E}" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="4" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile="$(OutDir)/ConfigLibrary.lib"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="4" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="WIN32;NDEBUG;_LIB" + RuntimeLibrary="0" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLibrarianTool" + OutputFile="$(OutDir)/ConfigLibrary.lib"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + <File + RelativePath=".\Config.cpp"> + </File> + <File + RelativePath=".\dotconfpp\dotconfpp.cpp"> + </File> + <File + RelativePath=".\dotconfpp\mempool.cpp"> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + <File + RelativePath=".\Config.h"> + </File> + <File + RelativePath=".\ConfigEnv.h"> + </File> + <File + RelativePath=".\dotconfpp\dotconfpp.h"> + </File> + <File + RelativePath=".\dotconfpp\mempool.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/src/server/shared/Config/dotconfpp/dotconfpp.cpp b/src/server/shared/Config/dotconfpp/dotconfpp.cpp new file mode 100644 index 00000000000..8760b118e38 --- /dev/null +++ b/src/server/shared/Config/dotconfpp/dotconfpp.cpp @@ -0,0 +1,599 @@ + +#include "Common.h" + +#include "dotconfpp.h" + +#ifdef WIN32 +#define PATH_MAX _MAX_PATH +#define strcasecmp stricmp +#define realpath(path,resolved_path) _fullpath(resolved_path, path, _MAX_PATH) +#include <io.h> +#else +#include <unistd.h> +#include <limits.h> +#include <stdint.h> +#include <strings.h> +#endif + +#if !defined(R_OK) +#define R_OK 04 +#endif + +DOTCONFDocumentNode::DOTCONFDocumentNode():previousNode(NULL), nextNode(NULL), parentNode(NULL), childNode(NULL), + values(NULL), valuesCount(0), + name(NULL), lineNum(0), fileName(NULL), closed(true) +{ +} + +DOTCONFDocumentNode::~DOTCONFDocumentNode() +{ + free(name); + if(values != NULL){ + for (int i = 0 ; i < valuesCount; i++){ + free(values[i]); + } + free(values); + } +} + +void DOTCONFDocumentNode::pushValue(char * _value) +{ + ++valuesCount; + values = (char**)realloc(values, valuesCount*sizeof(char*)); + values[valuesCount-1] = strdup(_value); +} + +const char* DOTCONFDocumentNode::getValue(int index) const +{ + if(index >= valuesCount){ + return NULL; + } + return values[index]; +} + +DOTCONFDocument::DOTCONFDocument(DOTCONFDocument::CaseSensitive caseSensitivity): + mempool(NULL), + curParent(NULL), curPrev(NULL), curLine(0), file(NULL), fileName(NULL) +{ + if(caseSensitivity == CASESENSETIVE){ + cmp_func = strcmp; + } else { + cmp_func = strcasecmp; + } + + mempool = new AsyncDNSMemPool(1024); + mempool->initialize(); +} + +DOTCONFDocument::~DOTCONFDocument() +{ + for (std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i != nodeTree.end(); ++i){ + delete(*i); + } + for (std::list<char*>::iterator i = requiredOptions.begin(); i != requiredOptions.end(); ++i){ + free(*i); + } + for (std::list<char*>::iterator i = processedFiles.begin(); i != processedFiles.end(); ++i){ + free(*i); + } + free(fileName); + delete mempool; +} + +int DOTCONFDocument::cleanupLine(char * line) +{ + char * start = line; + char * bg = line; + bool multiline = false; + bool concat = false; + char * word = NULL; + + if(!words.empty() && quoted) + concat = true; + + while(*line){ + if((*line == '#' || *line == ';') && !quoted){ + *bg = 0; + if(strlen(start)){ + + if(concat){ + word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1); + strcpy(word, words.back()); + strcat(word, start); + words.pop_back(); + concat = false; + } else { + word = mempool->strdup(start); + } + words.push_back(word); + } + break; + } + if(*line == '=' && !quoted){ + *line = ' ';continue; + } + + // Allowing \" in there causes problems with directory paths + // like "C:\TrinIty\" + //if(*line == '\\' && (*(line+1) == '"' || *(line+1) == '\'')){ + if(*line == '\\' && (*(line+1) == '\'')) { + *bg++ = *(line+1); + line+=2; continue; + } + if(*line == '\\' && *(line+1) == 'n'){ + *bg++ = '\n'; + line+=2; continue; + } + if(*line == '\\' && *(line+1) == 'r'){ + *bg++ = '\r'; + line+=2; continue; + } + if(*line == '\\' && (*(line+1) == '\n' || *(line+1) == '\r')){ + *bg = 0; + if(strlen(start)){ + + if(concat){ + word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1); + strcpy(word, words.back()); + strcat(word, start); + words.pop_back(); + concat = false; + } else { + word = mempool->strdup(start); + } + words.push_back(word); + } + multiline = true; + break; + } + if(*line == '"' || *line == '\''){ + quoted = !quoted; + ++line; continue; + } + if(isspace((unsigned char)*line) && !quoted){ + *bg++ = 0; + if(strlen(start)){ + + if(concat){ + word = (char*)mempool->alloc(strlen(words.back())+strlen(start)+1); + strcpy(word, words.back()); + strcat(word, start); + words.pop_back(); + concat = false; + } else { + word = mempool->strdup(start); + } + words.push_back(word); + } + start = bg; + while(isspace((unsigned char)*++line)) {} + + continue; + } + *bg++ = *line++; + } + + if(quoted && !multiline){ + error(curLine, fileName, "unterminated quote"); + return -1; + } + + return multiline?1:0; +} + +int DOTCONFDocument::parseLine() +{ + char * word = NULL; + char * nodeName = NULL; + char * nodeValue = NULL; + DOTCONFDocumentNode * tagNode = NULL; + bool newNode = false; + + for (std::list<char*>::iterator i = words.begin(); i != words.end(); ++i) { + word = *i; + + if(*word == '<'){ + newNode = true; + } + + if(newNode){ + nodeValue = NULL; + nodeName = NULL; + newNode = false; + } + + size_t wordLen = strlen(word); + if(word[wordLen-1] == '>'){ + word[wordLen-1] = 0; + newNode = true; + } + + if(nodeName == NULL){ + nodeName = word; + bool closed = true; + if(*nodeName == '<'){ + if(*(nodeName+1) != '/'){ + ++nodeName; + closed = false; + } else { + nodeName+=2; + std::list<DOTCONFDocumentNode*>::reverse_iterator itr=nodeTree.rbegin(); + for (; itr!=nodeTree.rend(); ++itr){ + if(!cmp_func(nodeName, (*itr)->name) && !(*itr)->closed){ + (*itr)->closed = true; + curParent = (*itr)->parentNode; + curPrev = *itr; + break; + } + } + if(itr==nodeTree.rend()){ + error(curLine, fileName, "not matched closing tag </%s>", nodeName); + return -1; + } + continue; + } + } + tagNode = new DOTCONFDocumentNode; + tagNode->name = strdup(nodeName); + tagNode->document = this; + tagNode->fileName = processedFiles.back(); + tagNode->lineNum = curLine; + tagNode->closed = closed; + if(!nodeTree.empty()){ + DOTCONFDocumentNode * prev = nodeTree.back(); + if(prev->closed){ + + curPrev->nextNode = tagNode; + tagNode->previousNode = curPrev; + tagNode->parentNode = curParent; + + } else { + prev->childNode = tagNode; + tagNode->parentNode = prev; + curParent = prev; + } + } + nodeTree.push_back(tagNode); + curPrev = tagNode; + } else { + nodeValue = word; + tagNode->pushValue(nodeValue); + } + } + + return 0; +} +int DOTCONFDocument::parseFile(DOTCONFDocumentNode * _parent) +{ + char str[512]; + int ret = 0; + curLine = 0; + curParent = _parent; + + quoted = false; + size_t slen = 0; + + while(fgets(str, 511, file)){ + ++curLine; + slen = strlen(str); + if( slen >= 510 ){ + error(curLine, fileName, "warning: line too long"); + } + if(str[slen-1] != '\n'){ + str[slen] = '\n'; + str[slen+1] = 0; + } + if((ret = cleanupLine(str)) == -1){ + break; + } + if(ret == 0){ + if(!words.empty()){ + ret = parseLine(); + mempool->free(); + words.clear(); + if(ret == -1){ + break; + } + } + } + } + + return ret; +} + +int DOTCONFDocument::checkConfig(const std::list<DOTCONFDocumentNode*>::iterator & from) +{ + int ret = 0; + + DOTCONFDocumentNode * tagNode = NULL; + int vi = 0; + for (std::list<DOTCONFDocumentNode*>::iterator i = from; i != nodeTree.end(); ++i){ + tagNode = *i; + if(!tagNode->closed){ + error(tagNode->lineNum, tagNode->fileName, "unclosed tag %s", tagNode->name); + ret = -1; + break; + } + vi = 0; + while( vi < tagNode->valuesCount ){ + + if(strstr(tagNode->values[vi], "${") && strchr(tagNode->values[vi], '}') ){ + ret = macroSubstitute(tagNode, vi ); + mempool->free(); + if(ret == -1){ + break; + } + } + ++vi; + } + if(ret == -1){ + break; + } + } + + return ret; +} + +int DOTCONFDocument::setContent(const char * _fileName) +{ + int ret = 0; + char realpathBuf[PATH_MAX]; + + if(realpath(_fileName, realpathBuf) == NULL){ + error(0, NULL, "realpath(%s) failed: %s", _fileName, strerror(errno)); + return -1; + } + + fileName = strdup(realpathBuf); + + processedFiles.push_back(strdup(realpathBuf)); + + if(( file = fopen(fileName, "r")) == NULL){ + error(0, NULL, "failed to open file '%s': %s", fileName, strerror(errno)); + return -1; + } + // Try read utf8 header and skip it if exist + uint32 utf8header = 0; + fgets((char*)&utf8header, 4, file); // Try read header + if (utf8header!=0x00BFBBEF) // If not exist + fseek(file, 0, SEEK_SET); // Reset read position + + ret = parseFile(); + + (void) fclose(file); + + if(!ret){ + + if( (ret = checkConfig(nodeTree.begin())) == -1){ + return -1; + } + + std::list<DOTCONFDocumentNode*>::iterator from; + DOTCONFDocumentNode * tagNode = NULL; + int vi = 0; + for (std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); ++i){ + tagNode = *i; + if(!cmp_func("DOTCONFPPIncludeFile", tagNode->name)){ + vi = 0; + while( vi < tagNode->valuesCount ){ + if(access(tagNode->values[vi], R_OK) == -1){ + error(tagNode->lineNum, tagNode->fileName, "%s: %s", tagNode->values[vi], strerror(errno)); + return -1; + } + if(realpath(tagNode->values[vi], realpathBuf) == NULL){ + error(tagNode->lineNum, tagNode->fileName, "realpath(%s) failed: %s", tagNode->values[vi], strerror(errno)); + return -1; + } + + bool processed = false; + for (std::list<char*>::const_iterator itInode = processedFiles.begin(); itInode != processedFiles.end(); ++itInode){ + if(!strcmp(*itInode, realpathBuf)){ + processed = true; + break; + } + } + if(processed){ + break; + } + + processedFiles.push_back(strdup(realpathBuf)); + + file = fopen(tagNode->values[vi], "r"); + if(file == NULL){ + error(tagNode->lineNum, fileName, "failed to open file '%s': %s", tagNode->values[vi], strerror(errno)); + return -1; + } + + fileName = strdup(realpathBuf); + from = nodeTree.end(); --from; + + ret = parseFile(); + (void) fclose(file); + if(ret == -1) + return -1; + if(checkConfig(++from) == -1){ + return -1; + } + ++vi; + } + } + } + + if(!requiredOptions.empty()) + ret = checkRequiredOptions(); + } + + return ret; +} + +int DOTCONFDocument::checkRequiredOptions() +{ + for (std::list<char*>::const_iterator ci = requiredOptions.begin(); ci != requiredOptions.end(); ++ci){ + bool matched = false; + for (std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); i!=nodeTree.end(); ++i){ + if(!cmp_func((*i)->name, *ci)){ + matched = true; + break; + } + } + if(!matched){ + error(0, NULL, "required option '%s' not specified", *ci); + return -1; + } + } + return 0; +} + +void DOTCONFDocument::error(int lineNum, const char * fileName_, const char * fmt, ...) +{ + va_list args; + va_start(args, fmt); + + size_t len = (lineNum!=0?strlen(fileName_):0) + strlen(fmt) + 50; + char * buf = (char*)mempool->alloc(len); + + if(lineNum) + (void) snprintf(buf, len, "DOTCONF++: file '%s', line %d: %s\n", fileName_, lineNum, fmt); + else + (void) snprintf(buf, len, "DOTCONF++: %s\n", fmt); + + (void) vfprintf(stderr, buf, args); + + va_end(args); +} + +char * DOTCONFDocument::getSubstitution(char * macro, int lineNum) +{ + char * buf = NULL; + char * variable = macro+2; + + char * endBr = strchr(macro, '}'); + + if(!endBr){ + error(lineNum, fileName, "unterminated '{'"); + return NULL; + } + *endBr = 0; + + char * defaultValue = strchr(variable, ':'); + + if(defaultValue){ + *defaultValue++ = 0; + if(*defaultValue != '-'){ + error(lineNum, fileName, "incorrect macro substitution syntax"); + return NULL; + } + ++defaultValue; + if(*defaultValue == '"' || *defaultValue == '\''){ + ++defaultValue; + defaultValue[strlen(defaultValue)-1] = 0; + } + } else { + defaultValue = NULL; + } + + char * subs = getenv(variable); + if( subs ){ + buf = mempool->strdup(subs); + } else { + std::list<DOTCONFDocumentNode*>::iterator i = nodeTree.begin(); + DOTCONFDocumentNode * tagNode = NULL; + for (; i!=nodeTree.end(); i++){ + tagNode = *i; + if(!cmp_func(tagNode->name, variable)){ + if(tagNode->valuesCount != 0){ + buf = mempool->strdup(tagNode->values[0]); + break; + } + } + } + if( i == nodeTree.end() ){ + if( defaultValue ){ + buf = mempool->strdup(defaultValue); + } else { + error(lineNum, fileName, "substitution not found and default value not given"); + return NULL; + } + } + } + return buf; +} + +int DOTCONFDocument::macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex) +{ + int ret = 0; + char * macro = tagNode->values[valueIndex]; + size_t valueLen = strlen(tagNode->values[valueIndex])+1; + char * value = (char*)mempool->alloc(valueLen); + char * v = value; + char * subs = NULL; + + while(*macro){ + if(*macro == '$' && *(macro+1) == '{'){ + char * m = strchr(macro, '}'); + subs = getSubstitution(macro, tagNode->lineNum); + if(subs == NULL){ + ret = -1; + break; + } + macro = m + 1; + *v = 0; + v = (char*)mempool->alloc(strlen(value)+strlen(subs)+valueLen); + strcpy(v, value); + value = strcat(v, subs); + v = value + strlen(value); + continue; + } + *v++ = *macro++; + } + *v = 0; + + free(tagNode->values[valueIndex]); + tagNode->values[valueIndex] = strdup(value); + return ret; +} + +const DOTCONFDocumentNode * DOTCONFDocument::getFirstNode() const +{ + if ( !nodeTree.empty() ) { + return *nodeTree.begin(); + } else { + return NULL; + } +} + +const DOTCONFDocumentNode * DOTCONFDocument::findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode, const DOTCONFDocumentNode * startNode) const +{ + + std::list<DOTCONFDocumentNode*>::const_iterator i = nodeTree.begin(); + + if(startNode == NULL) + startNode = parentNode; + + if(startNode != NULL){ + while( i != nodeTree.end() && (*i) != startNode ){ + ++i; + } + if( i != nodeTree.end() ) ++i; + } + + for (; i!=nodeTree.end(); ++i){ + + if((*i)->parentNode != parentNode){ + continue; + } + if(!cmp_func(nodeName, (*i)->name)){ + return *i; + } + } + return NULL; +} + +void DOTCONFDocument::setRequiredOptionNames(const char ** requiredOptionNames) +{ + while(*requiredOptionNames){ + requiredOptions.push_back(strdup( *requiredOptionNames )); + ++requiredOptionNames; + } +} + diff --git a/src/server/shared/Config/dotconfpp/dotconfpp.h b/src/server/shared/Config/dotconfpp/dotconfpp.h new file mode 100644 index 00000000000..554b152f693 --- /dev/null +++ b/src/server/shared/Config/dotconfpp/dotconfpp.h @@ -0,0 +1,97 @@ + + +#ifndef DOTCONFPP_H +#define DOTCONFPP_H + +#include <list> + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include "mempool.h" + +class DOTCONFDocument; + +class DOTCONFDocumentNode +{ +friend class DOTCONFDocument; +private: + DOTCONFDocumentNode * previousNode; + DOTCONFDocumentNode * nextNode; + DOTCONFDocumentNode * parentNode; + DOTCONFDocumentNode * childNode; + char ** values; + int valuesCount; + char * name; + const DOTCONFDocument * document; + int lineNum; + char * fileName; + bool closed; + + void pushValue(char * _value); + +public: + DOTCONFDocumentNode(); + ~DOTCONFDocumentNode(); + + const char * getConfigurationFileName()const { return fileName; } + int getConfigurationLineNumber() const { return lineNum; } + + const DOTCONFDocumentNode * getNextNode() const { return nextNode; } + const DOTCONFDocumentNode * getPreviuosNode() const { return previousNode; } + const DOTCONFDocumentNode * getParentNode() const { return parentNode; } + const DOTCONFDocumentNode * getChildNode() const { return childNode; } + const char* getValue(int index = 0) const; + const char * getName() const { return name; } + const DOTCONFDocument * getDocument() const { return document; } +}; + +class DOTCONFDocument +{ +public: + enum CaseSensitive { CASESENSETIVE, CASEINSENSETIVE }; +protected: + AsyncDNSMemPool * mempool; +private: + DOTCONFDocumentNode * curParent; + DOTCONFDocumentNode * curPrev; + int curLine; + bool quoted; + std::list<DOTCONFDocumentNode*> nodeTree; + std::list<char*> requiredOptions; + std::list<char*> processedFiles; + FILE * file; + char * fileName; + std::list<char*> words; + int (*cmp_func)(const char *, const char *); + + int checkRequiredOptions(); + int parseLine(); + int parseFile(DOTCONFDocumentNode * _parent = NULL); + int checkConfig(const std::list<DOTCONFDocumentNode*>::iterator & from); + int cleanupLine(char * line); + char * getSubstitution(char * macro, int lineNum); + int macroSubstitute(DOTCONFDocumentNode * tagNode, int valueIndex); + +protected: + virtual void error(int lineNum, const char * fileName, const char * fmt, ...) ATTR_PRINTF(4,5); + +public: + DOTCONFDocument(CaseSensitive caseSensitivity = CASESENSETIVE); + virtual ~DOTCONFDocument(); + + int setContent(const char * _fileName); + + void setRequiredOptionNames(const char ** requiredOptionNames); + const DOTCONFDocumentNode * getFirstNode() const; + const DOTCONFDocumentNode * findNode(const char * nodeName, const DOTCONFDocumentNode * parentNode = NULL, const DOTCONFDocumentNode * startNode = NULL) const; +}; + +#endif + diff --git a/src/server/shared/Config/dotconfpp/mempool.cpp b/src/server/shared/Config/dotconfpp/mempool.cpp new file mode 100644 index 00000000000..a23e33808bd --- /dev/null +++ b/src/server/shared/Config/dotconfpp/mempool.cpp @@ -0,0 +1,100 @@ + + +#include "mempool.h" + +AsyncDNSMemPool::PoolChunk::PoolChunk(size_t _size): + pool(NULL), pos(0), size(_size) +{ + pool = ::malloc(size); +} + +AsyncDNSMemPool::PoolChunk::~PoolChunk() +{ + ::free(pool); +} + +AsyncDNSMemPool::AsyncDNSMemPool(size_t _defaultSize): + chunks(NULL), chunksCount(0), defaultSize(_defaultSize), + poolUsage(0), poolUsageCounter(0) +{ +} + +AsyncDNSMemPool::~AsyncDNSMemPool() +{ + for (size_t i = 0; i<chunksCount; ++i){ + delete chunks[i]; + } + ::free(chunks); +} + +int AsyncDNSMemPool::initialize() +{ + chunksCount = 1; + chunks = (PoolChunk**)::malloc(sizeof(PoolChunk*)); + if(chunks == NULL) + return -1; + + chunks[chunksCount-1] = new PoolChunk(defaultSize); + + return 0; +} + +void AsyncDNSMemPool::addNewChunk(size_t size) +{ + ++chunksCount; + chunks = (PoolChunk**)::realloc(chunks, chunksCount*sizeof(PoolChunk*)); + if(size <= defaultSize) + chunks[chunksCount-1] = new PoolChunk(defaultSize); + else + chunks[chunksCount-1] = new PoolChunk(size); +} + +void * AsyncDNSMemPool::alloc(size_t size) +{ + PoolChunk * chunk = NULL; + for (size_t i = 0; i<chunksCount; ++i){ + chunk = chunks[i]; + if((chunk->size - chunk->pos) >= size){ + chunk->pos += size; + return ((char*)chunk->pool) + chunk->pos - size; + } + } + addNewChunk(size); + chunks[chunksCount-1]->pos = size; + return chunks[chunksCount-1]->pool; +} + +void AsyncDNSMemPool::free() +{ + size_t pu = 0; + size_t psz = 0; + ++poolUsageCounter; + + for (size_t i = 0; i<chunksCount; ++i){ + pu += chunks[i]->pos; + psz += chunks[i]->size; + chunks[i]->pos = 0; + } + poolUsage=(poolUsage>pu)?poolUsage:pu; + + if(poolUsageCounter >= 10 && chunksCount > 1){ + psz -= chunks[chunksCount-1]->size; + if(poolUsage < psz){ + --chunksCount; + delete chunks[chunksCount]; + } + poolUsage = 0; + poolUsageCounter = 0; + } +} + +void * AsyncDNSMemPool::calloc(size_t size) +{ + return ::memset(this->alloc(size), 0, size); +} + +char * AsyncDNSMemPool::strdup(const char *str) +{ + return ::strcpy((char*)this->alloc(strlen(str)+1), str); +} + diff --git a/src/server/shared/Config/dotconfpp/mempool.h b/src/server/shared/Config/dotconfpp/mempool.h new file mode 100644 index 00000000000..185b50798e1 --- /dev/null +++ b/src/server/shared/Config/dotconfpp/mempool.h @@ -0,0 +1,46 @@ + + +#ifndef ASYNC_DNS_MEMPOOL_H +#define ASYNC_DNS_MEMPOOL_H + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#undef free +#undef calloc +#undef strdup + +class AsyncDNSMemPool +{ +private: + struct PoolChunk { + void * pool; + size_t pos; + size_t size; + + PoolChunk(size_t _size); + ~PoolChunk(); + }; + PoolChunk ** chunks; + size_t chunksCount; + size_t defaultSize; + + size_t poolUsage; + size_t poolUsageCounter; + + void addNewChunk(size_t size); + +public: + AsyncDNSMemPool(size_t _defaultSize = 4096); + virtual ~AsyncDNSMemPool(); + + int initialize(); + void free(); + void * alloc(size_t size); + void * calloc(size_t size); + char * strdup(const char *str); +}; + +#endif + diff --git a/src/server/shared/Database/CMakeLists.txt b/src/server/shared/Database/CMakeLists.txt new file mode 100644 index 00000000000..405a5f89a57 --- /dev/null +++ b/src/server/shared/Database/CMakeLists.txt @@ -0,0 +1,30 @@ +SET(trinitydatabase_STAT_SRCS + DBCFileLoader.cpp + DBCFileLoader.h + DBCStore.h + Database.cpp + Database.h + DatabaseEnv.h + DatabaseImpl.h + Field.cpp + Field.h + QueryResult.cpp + QueryResult.h + SQLStorage.cpp + SQLStorage.h + SqlDelayThread.cpp + SqlDelayThread.h + SqlOperations.cpp + SqlOperations.h +) + +include_directories( + ${ACE_INCLUDE_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/src/shared + ${CMAKE_SOURCE_DIR}/src/shared/Database + ${CMAKE_SOURCE_DIR}/src/framework + ${MYSQL_INCLUDE_DIR} +) + +add_library(trinitydatabase STATIC ${trinitydatabase_STAT_SRCS}) diff --git a/src/server/shared/Database/DBCFileLoader.cpp b/src/server/shared/Database/DBCFileLoader.cpp new file mode 100644 index 00000000000..bad87a36fce --- /dev/null +++ b/src/server/shared/Database/DBCFileLoader.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "DBCFileLoader.h" + +DBCFileLoader::DBCFileLoader() +{ + data = NULL; + fieldsOffset = NULL; +} + +bool DBCFileLoader::Load(const char *filename, const char *fmt) +{ + uint32 header; + if (data) + { + delete [] data; + data = NULL; + } + + FILE * f = fopen(filename,"rb"); + if (!f) + return false; + + if (fread(&header,4,1,f)!=1) // Number of records + return false; + + EndianConvert(header); + + if (header!=0x43424457) + return false; //'WDBC' + + if (fread(&recordCount,4,1,f)!=1) // Number of records + return false; + + EndianConvert(recordCount); + + if (fread(&fieldCount,4,1,f)!=1) // Number of fields + return false; + + EndianConvert(fieldCount); + + if (fread(&recordSize,4,1,f)!=1) // Size of a record + return false; + + EndianConvert(recordSize); + + if (fread(&stringSize,4,1,f)!=1) // String size + return false; + + EndianConvert(stringSize); + + fieldsOffset = new uint32[fieldCount]; + fieldsOffset[0] = 0; + for (uint32 i = 1; i < fieldCount; i++) + { + fieldsOffset[i] = fieldsOffset[i - 1]; + if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields + fieldsOffset[i] += 1; + else // 4 byte fields (int32/float/strings) + fieldsOffset[i] += 4; + } + + data = new unsigned char[recordSize*recordCount+stringSize]; + stringTable = data + recordSize*recordCount; + + if (fread(data,recordSize*recordCount+stringSize,1,f)!=1) + return false; + + fclose(f); + + return true; +} + +DBCFileLoader::~DBCFileLoader() +{ + if (data) + delete [] data; + + if (fieldsOffset) + delete [] fieldsOffset; +} + +DBCFileLoader::Record DBCFileLoader::getRecord(size_t id) +{ + assert(data); + return Record(*this, data + id*recordSize); +} + +uint32 DBCFileLoader::GetFormatRecordSize(const char * format,int32* index_pos) +{ + uint32 recordsize = 0; + int32 i = -1; + for (uint32 x=0; format[x]; ++x) + { + switch(format[x]) + { + case FT_FLOAT: + case FT_INT: + recordsize+=4; + break; + case FT_STRING: + recordsize+=sizeof(char*); + break; + case FT_SORT: + i=x; + break; + case FT_IND: + i=x; + recordsize+=4; + break; + case FT_BYTE: + recordsize += 1; + break; + } + } + + if (index_pos) + *index_pos = i; + + return recordsize; +} + +char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char *& sqlDataTable) +{ + /* + format STRING, NA, FLOAT,NA,INT <=> + struct{ + char* field0, + float field1, + int field2 + }entry; + + this func will generate entry[rows] data; + */ + + typedef char * ptr; + if (strlen(format)!=fieldCount) + return NULL; + + //get struct size and index pos + int32 i; + uint32 recordsize=GetFormatRecordSize(format,&i); + + if (i>=0) + { + uint32 maxi=0; + //find max index + for (uint32 y=0; y<recordCount; y++) + { + uint32 ind=getRecord(y).getUInt (i); + if(ind>maxi)maxi=ind; + } + + // If higher index avalible from sql - use it instead of dbcs + if (sqlHighestIndex > maxi) + maxi = sqlHighestIndex; + + ++maxi; + records=maxi; + indexTable=new ptr[maxi]; + memset(indexTable,0,maxi*sizeof(ptr)); + } + else + { + records = recordCount + sqlRecordCount; + indexTable = new ptr[recordCount+ sqlRecordCount]; + } + + char* dataTable= new char[(recordCount + sqlRecordCount)*recordsize]; + + uint32 offset=0; + + for (uint32 y =0; y<recordCount; ++y) + { + if(i>=0) + indexTable[getRecord(y).getUInt(i)]=&dataTable[offset]; + else + indexTable[y]=&dataTable[offset]; + + for (uint32 x=0; x<fieldCount; x++) + { + switch(format[x]) + { + case FT_FLOAT: + *((float*)(&dataTable[offset]))=getRecord(y).getFloat(x); + offset+=4; + break; + case FT_IND: + case FT_INT: + *((uint32*)(&dataTable[offset]))=getRecord(y).getUInt(x); + offset+=4; + break; + case FT_BYTE: + *((uint8*)(&dataTable[offset]))=getRecord(y).getUInt8(x); + offset+=1; + break; + case FT_STRING: + *((char**)(&dataTable[offset]))=NULL; // will be replaces non-empty or "" strings in AutoProduceStrings + offset+=sizeof(char*); + break; + } + } + } + + sqlDataTable = dataTable + offset; + + return dataTable; +} + +char* DBCFileLoader::AutoProduceStrings(const char* format, char* dataTable) +{ + if (strlen(format)!=fieldCount) + return NULL; + + char* stringPool= new char[stringSize]; + memcpy(stringPool,stringTable,stringSize); + + uint32 offset=0; + + for (uint32 y =0; y<recordCount; y++) + { + for (uint32 x=0; x<fieldCount; x++) + switch(format[x]) + { + case FT_FLOAT: + case FT_IND: + case FT_INT: + offset+=4; + break; + case FT_BYTE: + offset+=1; + break; + case FT_STRING: + // fill only not filled entries + char** slot = (char**)(&dataTable[offset]); + if(!*slot || !**slot) + { + const char * st = getRecord(y).getString(x); + *slot=stringPool+(st-(const char*)stringTable); + } + offset+=sizeof(char*); + break; + } + } + + return stringPool; +} + diff --git a/src/server/shared/Database/DBCFileLoader.h b/src/server/shared/Database/DBCFileLoader.h new file mode 100644 index 00000000000..a97ab4d60fa --- /dev/null +++ b/src/server/shared/Database/DBCFileLoader.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DBC_FILE_LOADER_H +#define DBC_FILE_LOADER_H +#include "Platform/Define.h" +#include "Utilities/ByteConverter.h" +#include <cassert> + +enum +{ + FT_NA='x', //not used or unknown, 4 byte size + FT_NA_BYTE='X', //not used or unknown, byte + FT_STRING='s', //char* + FT_FLOAT='f', //float + FT_INT='i', //uint32 + FT_BYTE='b', //uint8 + FT_SORT='d', //sorted by this field, field is not included + FT_IND='n', //the same,but parsed to data + FT_LOGIC='l', //Logical (boolean) + FT_SQL_PRESENT='p', //Used in sql format to mark column present in sql dbc + FT_SQL_ABSENT='a' //Used in sql format to mark column absent in sql dbc +}; + +class DBCFileLoader +{ + public: + DBCFileLoader(); + ~DBCFileLoader(); + + bool Load(const char *filename, const char *fmt); + + class Record + { + public: + float getFloat(size_t field) const + { + assert(field < file.fieldCount); + float val = *reinterpret_cast<float*>(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint32 getUInt(size_t field) const + { + assert(field < file.fieldCount); + uint32 val = *reinterpret_cast<uint32*>(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint8 getUInt8(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast<uint8*>(offset+file.GetOffset(field)); + } + + const char *getString(size_t field) const + { + assert(field < file.fieldCount); + size_t stringOffset = getUInt(field); + assert(stringOffset < file.stringSize); + return reinterpret_cast<char*>(file.stringTable + stringOffset); + } + + private: + Record(DBCFileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) {} + unsigned char *offset; + DBCFileLoader &file; + + friend class DBCFileLoader; + + }; + + // Get record by id + Record getRecord(size_t id); + /// Get begin iterator over records + + uint32 GetNumRows() const { return recordCount; } + uint32 GetRowSize() const { return recordSize; } + uint32 GetCols() const { return fieldCount; } + uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; } + bool IsLoaded() { return data != NULL; } + char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char *& sqlDataTable); + char* AutoProduceStrings(const char* fmt, char* dataTable); + static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL); + private: + + uint32 recordSize; + uint32 recordCount; + uint32 fieldCount; + uint32 stringSize; + uint32 *fieldsOffset; + unsigned char *data; + unsigned char *stringTable; +}; +#endif diff --git a/src/server/shared/Database/DBCStore.h b/src/server/shared/Database/DBCStore.h new file mode 100644 index 00000000000..61e2f7a6d06 --- /dev/null +++ b/src/server/shared/Database/DBCStore.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DBCSTORE_H +#define DBCSTORE_H + +#include "DBCFileLoader.h" +#include "Log.h" + +struct SqlDbc +{ + const std::string * formatString; + const std::string * indexName; + std::string sqlTableName; + int32 indexPos; + int32 sqlIndexPos; + SqlDbc(const std::string * _filename, const std::string * _format, const std::string * _idname, const char * fmt) + :formatString(_format),sqlIndexPos(0), indexName (_idname) + { + // Convert dbc file name to sql table name + sqlTableName = *_filename; + for (uint32 i = 0; i< sqlTableName.size(); ++i) + { + if (isalpha(sqlTableName[i])) + sqlTableName[i] = tolower(sqlTableName[i]); + else if (sqlTableName[i] == '.') + sqlTableName[i] = '_'; + } + + // Get sql index position + DBCFileLoader::GetFormatRecordSize(fmt, &indexPos); + if (indexPos>=0) + { + for (int32 x=0; x < formatString->size(); x++) + { + // Count only fields present in sql + if ((*formatString)[x] == FT_SQL_PRESENT) + { + if (x == indexPos) + break; + ++sqlIndexPos; + } + } + } + } +}; + +template<class T> +class DBCStorage +{ + typedef std::list<char*> StringPoolList; + public: + explicit DBCStorage(const char *f) : nCount(0), fieldCount(0), fmt(f), indexTable(NULL), m_dataTable(NULL) { } + ~DBCStorage() { Clear(); } + + T const* LookupEntry(uint32 id) const { return (id>=nCount)?NULL:indexTable[id]; } + uint32 GetNumRows() const { return nCount; } + char const* GetFormat() const { return fmt; } + uint32 GetFieldCount() const { return fieldCount; } + + bool Load(char const* fn, SqlDbc * sql) + { + DBCFileLoader dbc; + // Check if load was sucessful, only then continue + if (!dbc.Load(fn, fmt)) + return false; + + uint32 sqlRecordCount = 0; + uint32 sqlHighestIndex = 0; + Field *fields = NULL; + QueryResult_AutoPtr result = QueryResult_AutoPtr(NULL); + // Load data from sql + if (sql) + { + std::string query = "SELECT * FROM " + sql->sqlTableName; + if (sql->indexPos >= 0) + query +=" ORDER BY + " + *sql->indexName + " DESC"; + query += ";"; + + result = WorldDatabase.Query(query.c_str()); + if (result) + { + sqlRecordCount = result->GetRowCount(); + if (sql->indexPos >= 0) + { + fields = result->Fetch(); + sqlHighestIndex = fields[sql->sqlIndexPos].GetUInt32(); + } + // Check if sql index pos is valid + if (int32(result->GetFieldCount()-1) < sql->sqlIndexPos) + { + sLog.outError("Invalid index pos for dbc:'%s'", sql->sqlTableName.c_str()); + return false; + } + } + } + char * sqlDataTable; + fieldCount = dbc.GetCols(); + m_dataTable = (T*)dbc.AutoProduceData(fmt,nCount,(char**&)indexTable, sqlRecordCount, sqlHighestIndex, sqlDataTable); + + m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable)); + + // Insert sql data into arrays + if (result) + { + if (indexTable) + { + uint32 offset = 0; + uint32 rowIndex = dbc.GetNumRows(); + do + { + if (!fields) + fields = result->Fetch(); + + if(sql->indexPos >= 0) + { + uint32 id = fields[sql->sqlIndexPos].GetUInt32(); + if (indexTable[id]) + { + sLog.outError("Index %d already exists in dbc:'%s'", id, sql->sqlTableName.c_str()); + return false; + } + indexTable[id]=(T*)&sqlDataTable[offset]; + } + else + indexTable[rowIndex]=(T*)&sqlDataTable[offset]; + uint32 columnNumber = 0; + uint32 sqlColumnNumber = 0; + + for (; columnNumber < sql->formatString->size(); ++columnNumber) + { + if ((*sql->formatString)[columnNumber] == FT_SQL_ABSENT) + { + switch(fmt[columnNumber]) + { + case FT_FLOAT: + *((float*)(&sqlDataTable[offset]))= 0.0f; + offset+=4; + break; + case FT_IND: + case FT_INT: + *((uint32*)(&sqlDataTable[offset]))=uint32(0); + offset+=4; + break; + case FT_BYTE: + *((uint8*)(&sqlDataTable[offset]))=uint8(0); + offset+=1; + break; + case FT_STRING: + // Beginning of the pool - empty string + *((char**)(&sqlDataTable[offset]))=m_stringPoolList.back(); + offset+=sizeof(char*); + break; + } + } + else if ((*sql->formatString)[columnNumber] == FT_SQL_PRESENT) + { + bool validSqlColumn = true; + switch(fmt[columnNumber]) + { + case FT_FLOAT: + *((float*)(&sqlDataTable[offset]))=fields[sqlColumnNumber].GetFloat(); + offset+=4; + break; + case FT_IND: + case FT_INT: + *((uint32*)(&sqlDataTable[offset]))=fields[sqlColumnNumber].GetUInt32(); + offset+=4; + break; + case FT_BYTE: + *((uint8*)(&sqlDataTable[offset]))=fields[sqlColumnNumber].GetUInt8(); + offset+=1; + break; + case FT_STRING: + sLog.outError("Unsupported data type in table '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); + return false; + case FT_SORT: + break; + default: + validSqlColumn = false; + } + if (validSqlColumn && (columnNumber != (sql->formatString->size()-1))) + sqlColumnNumber++; + } + else + { + sLog.outError("Incorrect sql format string '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); + return false; + } + } + if (sqlColumnNumber != (result->GetFieldCount()-1)) + { + sLog.outError("SQL and DBC format strings are not matching for table: '%s'", sql->sqlTableName.c_str()); + return false; + } + + fields = NULL; + ++rowIndex; + }while (result->NextRow()); + } + } + + // error in dbc file at loading if NULL + return indexTable!=NULL; + } + + bool LoadStringsFrom(char const* fn) + { + // DBC must be already loaded using Load + if(!indexTable) + return false; + + DBCFileLoader dbc; + // Check if load was successful, only then continue + if(!dbc.Load(fn, fmt)) + return false; + + m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable)); + + return true; + } + + void Clear() + { + if (!indexTable) + return; + + delete[] ((char*)indexTable); + indexTable = NULL; + delete[] ((char*)m_dataTable); + m_dataTable = NULL; + + while(!m_stringPoolList.empty()) + { + delete[] m_stringPoolList.front(); + m_stringPoolList.pop_front(); + } + nCount = 0; + } + + private: + char const* fmt; + uint32 nCount; + uint32 fieldCount; + T** indexTable; + T* m_dataTable; + StringPoolList m_stringPoolList; +}; + +#endif diff --git a/src/server/shared/Database/Database.cpp b/src/server/shared/Database/Database.cpp new file mode 100644 index 00000000000..379388d7997 --- /dev/null +++ b/src/server/shared/Database/Database.cpp @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DatabaseEnv.h" +#include "Config/ConfigEnv.h" + +#include "Common.h" +#include "../../game/UpdateFields.h" + +#include "Util.h" +#include "Policies/SingletonImp.h" +#include "Platform/Define.h" +#include "Threading.h" +#include "Database/SqlDelayThread.h" +#include "Database/SqlOperations.h" +#include "Timer.h" + + +#include <ctime> +#include <iostream> +#include <fstream> + +size_t Database::db_count = 0; + +Database::Database() : mMysql(NULL) +{ + // before first connection + if (db_count++ == 0) + { + // Mysql Library Init + mysql_library_init(-1, NULL, NULL); + + if (!mysql_thread_safe()) + { + sLog.outError("FATAL ERROR: Used MySQL library isn't thread-safe."); + exit(1); + } + } +} + +Database::~Database() +{ + if (m_delayThread) + HaltDelayThread(); + + if (mMysql) + mysql_close(mMysql); + + // Free Mysql library pointers for last ~DB + if (--db_count == 0) + mysql_library_end(); +} + +bool Database::Initialize(const char *infoString) +{ + // Enable logging of SQL commands (usally only GM commands) + // (See method: PExecuteLog) + m_logSQL = sConfig.GetBoolDefault("LogSQL", false); + m_logsDir = sConfig.GetStringDefault("LogsDir",""); + if (!m_logsDir.empty()) + { + if ((m_logsDir.at(m_logsDir.length()-1)!='/') && (m_logsDir.at(m_logsDir.length()-1)!='\\')) + m_logsDir.append("/"); + } + + tranThread = NULL; + MYSQL *mysqlInit; + mysqlInit = mysql_init(NULL); + if (!mysqlInit) + { + sLog.outError("Could not initialize Mysql connection"); + return false; + } + + InitDelayThread(); + + Tokens tokens = StrSplit(infoString, ";"); + + Tokens::iterator iter; + + std::string host, port_or_socket, user, password, database; + int port; + char const* unix_socket; + + iter = tokens.begin(); + + if (iter != tokens.end()) + host = *iter++; + if (iter != tokens.end()) + port_or_socket = *iter++; + if (iter != tokens.end()) + user = *iter++; + if (iter != tokens.end()) + password = *iter++; + if (iter != tokens.end()) + database = *iter++; + + mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8"); + #ifdef WIN32 + if (host==".") // named pipe use option (Windows) + { + unsigned int opt = MYSQL_PROTOCOL_PIPE; + mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt); + port = 0; + unix_socket = 0; + } + else // generic case + { + port = atoi(port_or_socket.c_str()); + unix_socket = 0; + } + #else + if (host==".") // socket use option (Unix/Linux) + { + unsigned int opt = MYSQL_PROTOCOL_SOCKET; + mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt); + host = "localhost"; + port = 0; + unix_socket = port_or_socket.c_str(); + } + else // generic case + { + port = atoi(port_or_socket.c_str()); + unix_socket = 0; + } + #endif + + mMysql = mysql_real_connect(mysqlInit, host.c_str(), user.c_str(), + password.c_str(), database.c_str(), port, unix_socket, 0); + + if (mMysql) + { + sLog.outDetail("Connected to MySQL database at %s", host.c_str()); + sLog.outString("MySQL client library: %s", mysql_get_client_info()); + sLog.outString("MySQL server ver: %s ", mysql_get_server_info( mMysql)); + + if (!mysql_autocommit(mMysql, 1)) + sLog.outDetail("AUTOCOMMIT SUCCESSFULLY SET TO 1"); + else + sLog.outDetail("AUTOCOMMIT NOT SET TO 1"); + + // set connection properties to UTF8 to properly handle locales for different + // server configs - core sends data in UTF8, so MySQL must expect UTF8 too + PExecute("SET NAMES `utf8`"); + PExecute("SET CHARACTER SET `utf8`"); + + #if MYSQL_VERSION_ID >= 50003 + my_bool my_true = (my_bool)1; + if (mysql_options(mMysql, MYSQL_OPT_RECONNECT, &my_true)) + sLog.outDetail("Failed to turn on MYSQL_OPT_RECONNECT."); + else + sLog.outDetail("Successfully turned on MYSQL_OPT_RECONNECT."); + #else + #warning "Your mySQL client lib version does not support reconnecting after a timeout.\nIf this causes you any trouble we advice you to upgrade your mySQL client libs to at least mySQL 5.0.13 to resolve this problem." + #endif + return true; + } + else + { + sLog.outError("Could not connect to MySQL database at %s: %s\n", host.c_str(),mysql_error(mysqlInit)); + mysql_close(mysqlInit); + return false; + } +} + +void Database::ThreadStart() +{ + mysql_thread_init(); +} + +void Database::ThreadEnd() +{ + mysql_thread_end(); +} + +void Database::escape_string(std::string& str) +{ + if (str.empty()) + return; + + char* buf = new char[str.size()*2+1]; + escape_string(buf,str.c_str(),str.size()); + str = buf; + delete[] buf; +} + +unsigned long Database::escape_string(char *to, const char *from, unsigned long length) +{ + if (!mMysql || !to || !from || !length) + return 0; + + return(mysql_real_escape_string(mMysql, to, from, length)); +} + + +bool Database::PExecuteLog(const char * format,...) +{ + if (!format) + return false; + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap); + va_end(ap); + + if (res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return false; + } + + if (m_logSQL) + { + time_t curr; + tm local; + time(&curr); // get current time_t value + local=*(localtime(&curr)); // dereference and assign + char fName[128]; + sprintf(fName, "%04d-%02d-%02d_logSQL.sql", local.tm_year+1900, local.tm_mon+1, local.tm_mday); + + FILE* log_file; + std::string logsDir_fname = m_logsDir+fName; + log_file = fopen(logsDir_fname.c_str(), "a"); + if (log_file) + { + fprintf(log_file, "%s;\n", szQuery); + fclose(log_file); + } + else + { + // The file could not be opened + sLog.outError("SQL-Logging is disabled - Log file for the SQL commands could not be openend: %s",fName); + } + } + + return Execute(szQuery); +} + +void Database::SetResultQueue(SqlResultQueue * queue) +{ + m_queryQueues[ACE_Based::Thread::current()] = queue; +} + +bool Database::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) +{ + if (!mMysql) + return 0; + + { + // guarded block for thread-safe mySQL request + ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex); + #ifdef TRINITY_DEBUG + uint32 _s = getMSTime(); + #endif + if (mysql_query(mMysql, sql)) + { + sLog.outErrorDb("SQL: %s", sql); + sLog.outErrorDb("query ERROR: %s", mysql_error(mMysql)); + return false; + } + else + { + #ifdef TRINITY_DEBUG + sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql ); + #endif + } + + *pResult = mysql_store_result(mMysql); + *pRowCount = mysql_affected_rows(mMysql); + *pFieldCount = mysql_field_count(mMysql); + } + + if (!*pResult ) + return false; + + if (!*pRowCount) + { + mysql_free_result(*pResult); + return false; + } + + *pFields = mysql_fetch_fields(*pResult); + return true; +} + +QueryResult_AutoPtr Database::Query(const char *sql) +{ + MYSQL_RES *result = NULL; + MYSQL_FIELD *fields = NULL; + uint64 rowCount = 0; + uint32 fieldCount = 0; + + if (!_Query(sql, &result, &fields, &rowCount, &fieldCount)) + return QueryResult_AutoPtr(NULL); + + QueryResult *queryResult = new QueryResult(result, fields, rowCount, fieldCount); + + queryResult->NextRow(); + + return QueryResult_AutoPtr(queryResult); +} + +QueryResult_AutoPtr Database::PQuery(const char *format,...) +{ + if (!format) + return QueryResult_AutoPtr(NULL); + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap); + va_end(ap); + + if (res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return QueryResult_AutoPtr(NULL); + } + + return Query(szQuery); +} + +QueryNamedResult* Database::QueryNamed(const char *sql) +{ + MYSQL_RES *result = NULL; + MYSQL_FIELD *fields = NULL; + uint64 rowCount = 0; + uint32 fieldCount = 0; + + if (!_Query(sql, &result, &fields, &rowCount, &fieldCount)) + return NULL; + + QueryFieldNames names(fieldCount); + for (uint32 i = 0; i < fieldCount; i++) + names[i] = fields[i].name; + + QueryResult *queryResult = new QueryResult(result, fields, rowCount, fieldCount); + + queryResult->NextRow(); + + return new QueryNamedResult(queryResult, names); +} + +QueryNamedResult* Database::PQueryNamed(const char *format,...) +{ + if (!format) + return NULL; + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap); + va_end(ap); + + if (res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return false; + } + + return QueryNamed(szQuery); +} + +bool Database::Execute(const char *sql) +{ + if (!mMysql) + return false; + + // don't use queued execution if it has not been initialized + if (!m_threadBody) + return DirectExecute(sql); + + nMutex.acquire(); + tranThread = ACE_Based::Thread::current(); // owner of this transaction + TransactionQueues::iterator i = m_tranQueues.find(tranThread); + if (i != m_tranQueues.end() && i->second != NULL) + i->second->DelayExecute(sql); // Statement for transaction + else + m_threadBody->Delay(new SqlStatement(sql)); // Simple sql statement + + nMutex.release(); + return true; +} + +bool Database::PExecute(const char * format,...) +{ + if (!format) + return false; + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap); + va_end(ap); + + if (res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return false; + } + + return Execute(szQuery); +} + +bool Database::_UpdateDataBlobValue(const uint32 guid, const uint32 field, const int32 value) +{ + return PExecute( + "UPDATE characters SET data=" + "CONCAT(SUBSTRING_INDEX(`data`,' ',%u),' '," + "GREATEST(SUBSTRING_INDEX(SUBSTRING_INDEX(`data`,' ',%u),' ',-1)+%i,0)," + "' ',SUBSTRING_INDEX(`data`,' ',%i)) WHERE guid=%u", + field, field+1, value, -int32(PLAYER_END-field), guid); +} + +bool Database::_SetDataBlobValue(const uint32 guid, const uint32 field, const uint32 value) +{ + return PExecute( + "UPDATE characters SET data=" + "CONCAT(SUBSTRING_INDEX(`data`,' ',%u),' '," + "%u,' ',SUBSTRING_INDEX(`data`,' ',%i)) WHERE guid=%u", + field, value, -int32(PLAYER_END-field), guid); +} + +bool Database::DirectExecute(const char* sql) +{ + if (!mMysql) + return false; + + { + // guarded block for thread-safe mySQL request + ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex); + + #ifdef TRINITY_DEBUG + uint32 _s = getMSTime(); + #endif + if (mysql_query(mMysql, sql)) + { + sLog.outErrorDb("SQL: %s", sql); + sLog.outErrorDb("SQL ERROR: %s", mysql_error(mMysql)); + return false; + } + else + { + #ifdef TRINITY_DEBUG + sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql); + #endif + } + } + + return true; +} + +bool Database::DirectPExecute(const char * format,...) +{ + if (!format) + return false; + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap); + va_end(ap); + + if (res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return false; + } + + return DirectExecute(szQuery); +} + +bool Database::CheckRequiredField(char const* table_name, char const* required_name) +{ + // check required field + QueryResult_AutoPtr result = PQuery("SELECT %s FROM %s LIMIT 1",required_name,table_name); + if (result) + return true; + + // check fail, prepare readabale error message + + // search current required_* field in DB + QueryNamedResult* result2 = PQueryNamed("SELECT * FROM %s LIMIT 1",table_name); + if (result2) + { + QueryFieldNames const& namesMap = result2->GetFieldNames(); + std::string reqName; + for (QueryFieldNames::const_iterator itr = namesMap.begin(); itr != namesMap.end(); ++itr) + { + if (itr->substr(0,9)=="required_") + { + reqName = *itr; + break; + } + } + + delete result2; + + if (!reqName.empty()) + sLog.outErrorDb("Table `%s` have field `%s` but expected `%s`! Not all sql updates applied?",table_name,reqName.c_str(),required_name); + else + sLog.outErrorDb("Table `%s` not have required_* field but expected `%s`! Not all sql updates applied?",table_name,required_name); + } + else + sLog.outErrorDb("Table `%s` fields list query fail but expected have `%s`! No records in `%s`?",table_name,required_name,table_name); + + return false; +} + +bool Database::_TransactionCmd(const char *sql) +{ + if (mysql_query(mMysql, sql)) + { + sLog.outError("SQL: %s", sql); + sLog.outError("SQL ERROR: %s", mysql_error(mMysql)); + return false; + } + else + DEBUG_LOG("SQL: %s", sql); + + return true; +} + +bool Database::BeginTransaction() +{ + if (!mMysql) + return false; + + // don't use queued execution if it has not been initialized + if (!m_threadBody) + { + if (tranThread == ACE_Based::Thread::current()) + return false; // huh? this thread already started transaction + + mMutex.acquire(); + if (!_TransactionCmd("START TRANSACTION")) + { + mMutex.release(); // can't start transaction + return false; + } + return true; // transaction started + } + + nMutex.acquire(); + tranThread = ACE_Based::Thread::current(); // owner of this transaction + TransactionQueues::iterator i = m_tranQueues.find(tranThread); + if (i != m_tranQueues.end() && i->second != NULL) + // If for thread exists queue and also contains transaction + // delete that transaction (not allow trans in trans) + delete i->second; + + m_tranQueues[tranThread] = new SqlTransaction(); + nMutex.release(); + return true; +} + +bool Database::CommitTransaction() +{ + if (!mMysql) + return false; + + bool _res = false; + + // don't use queued execution if it has not been initialized + if (!m_threadBody) + { + if (tranThread != ACE_Based::Thread::current()) + return false; + + _res = _TransactionCmd("COMMIT"); + tranThread = NULL; + mMutex.release(); + return _res; + } + + nMutex.acquire(); + tranThread = ACE_Based::Thread::current(); + TransactionQueues::iterator i = m_tranQueues.find(tranThread); + if (i != m_tranQueues.end() && i->second != NULL) + { + m_threadBody->Delay(i->second); + m_tranQueues.erase(i); + _res = true; + } + nMutex.release(); + return _res; +} + +bool Database::RollbackTransaction() +{ + if (!mMysql) + return false; + + // don't use queued execution if it has not been initialized + if (!m_threadBody) + { + if (tranThread != ACE_Based::Thread::current()) + return false; + + bool _res = _TransactionCmd("ROLLBACK"); + tranThread = NULL; + mMutex.release(); + return _res; + } + + nMutex.acquire(); + tranThread = ACE_Based::Thread::current(); + TransactionQueues::iterator i = m_tranQueues.find(tranThread); + if (i != m_tranQueues.end() && i->second != NULL) + { + delete i->second; + i->second = NULL; + m_tranQueues.erase(i); + } + nMutex.release(); + return true; +} + +void Database::InitDelayThread() +{ + assert(!m_delayThread); + + //New delay thread for delay execute + m_threadBody = new SqlDelayThread(this); // will deleted at m_delayThread delete + m_delayThread = new ACE_Based::Thread(m_threadBody); +} + +void Database::HaltDelayThread() +{ + if (!m_threadBody || !m_delayThread) + return; + + m_threadBody->Stop(); //Stop event + m_delayThread->wait(); //Wait for flush to DB + delete m_delayThread; //This also deletes m_threadBody + m_delayThread = NULL; + m_threadBody = NULL; +} + diff --git a/src/server/shared/Database/Database.h b/src/server/shared/Database/Database.h new file mode 100644 index 00000000000..4ad5d29c993 --- /dev/null +++ b/src/server/shared/Database/Database.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DATABASE_H +#define DATABASE_H + +#include "Threading.h" +#include "Utilities/UnorderedMap.h" +#include "Database/SqlDelayThread.h" +#include "Policies/Singleton.h" +#include "ace/Thread_Mutex.h" +#include "ace/Guard_T.h" + +#ifdef WIN32 +#define FD_SETSIZE 1024 +#include <winsock2.h> +#include <mysql/mysql.h> +#else +#include <mysql.h> +#endif + +class SqlTransaction; +class SqlResultQueue; +class SqlQueryHolder; + +typedef UNORDERED_MAP<ACE_Based::Thread* , SqlTransaction*> TransactionQueues; +typedef UNORDERED_MAP<ACE_Based::Thread* , SqlResultQueue*> QueryQueues; + +#define MAX_QUERY_LEN 32*1024 + +class Database +{ + protected: + TransactionQueues m_tranQueues; ///< Transaction queues from diff. threads + QueryQueues m_queryQueues; ///< Query queues from diff threads + SqlDelayThread* m_threadBody; ///< Pointer to delay sql executer (owned by m_delayThread) + ACE_Based::Thread* m_delayThread; ///< Pointer to executer thread + + public: + + Database(); + ~Database(); + + /*! infoString should be formated like hostname;username;password;database. */ + bool Initialize(const char *infoString); + + void InitDelayThread(); + void HaltDelayThread(); + + QueryResult_AutoPtr Query(const char *sql); + QueryResult_AutoPtr PQuery(const char *format,...) ATTR_PRINTF(2,3); + QueryNamedResult* QueryNamed(const char *sql); + QueryNamedResult* PQueryNamed(const char *format,...) ATTR_PRINTF(2,3); + + /// Async queries and query holders, implemented in DatabaseImpl.h + + // Query / member + template<class Class> + bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *sql); + template<class Class, typename ParamType1> + bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql); + template<class Class, typename ParamType1, typename ParamType2> + bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql); + template<class Class, typename ParamType1, typename ParamType2, typename ParamType3> + bool AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql); + // Query / static + template<typename ParamType1> + bool AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql); + template<typename ParamType1, typename ParamType2> + bool AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql); + template<typename ParamType1, typename ParamType2, typename ParamType3> + bool AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql); + // PQuery / member + template<class Class> + bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *format,...) ATTR_PRINTF(4,5); + template<class Class, typename ParamType1> + bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(5,6); + template<class Class, typename ParamType1, typename ParamType2> + bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...) ATTR_PRINTF(6,7); + template<class Class, typename ParamType1, typename ParamType2, typename ParamType3> + bool AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) ATTR_PRINTF(7,8); + // PQuery / static + template<typename ParamType1> + bool AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...) ATTR_PRINTF(4,5); + template<typename ParamType1, typename ParamType2> + bool AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...) ATTR_PRINTF(5,6); + template<typename ParamType1, typename ParamType2, typename ParamType3> + bool AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) ATTR_PRINTF(6,7); + template<class Class> + // QueryHolder + bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SqlQueryHolder*), SqlQueryHolder *holder); + template<class Class, typename ParamType1> + bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1); + + bool Execute(const char *sql); + bool PExecute(const char *format,...) ATTR_PRINTF(2,3); + bool DirectExecute(const char* sql); + bool DirectPExecute(const char *format,...) ATTR_PRINTF(2,3); + + bool _UpdateDataBlobValue(const uint32 guid, const uint32 field, const int32 value); + bool _SetDataBlobValue(const uint32 guid, const uint32 field, const uint32 value); + + // Writes SQL commands to a LOG file (see Trinityd.conf "LogSQL") + bool PExecuteLog(const char *format,...) ATTR_PRINTF(2,3); + + bool BeginTransaction(); + bool CommitTransaction(); + bool RollbackTransaction(); + + operator bool () const { return mMysql != NULL; } + unsigned long escape_string(char *to, const char *from, unsigned long length); + void escape_string(std::string& str); + + void ThreadStart(); + void ThreadEnd(); + + // sets the result queue of the current thread, be careful what thread you call this from + void SetResultQueue(SqlResultQueue * queue); + + bool CheckRequiredField(char const* table_name, char const* required_name); + + private: + bool m_logSQL; + std::string m_logsDir; + ACE_Thread_Mutex mMutex; // For thread safe operations between core and mySQL server + ACE_Thread_Mutex nMutex; // For thread safe operations on m_transQueues + + ACE_Based::Thread * tranThread; + + MYSQL *mMysql; + + static size_t db_count; + + bool _TransactionCmd(const char *sql); + bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount); +}; +#endif + diff --git a/src/server/shared/Database/DatabaseEnv.h b/src/server/shared/Database/DatabaseEnv.h new file mode 100644 index 00000000000..69236b076e9 --- /dev/null +++ b/src/server/shared/Database/DatabaseEnv.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(DATABASEENV_H) +#define DATABASEENV_H + +#include "Common.h" +#include "Log.h" +#include "Errors.h" + +#include "Database/Field.h" +#include "Database/QueryResult.h" + +#include "Database/Database.h" +typedef Database DatabaseType; +#define _LIKE_ "LIKE" +#define _TABLE_SIM_ "`" +#define _CONCAT3_(A,B,C) "CONCAT( " A " , " B " , " C " )" +#define _OFFSET_ "LIMIT %d,1" + +extern DatabaseType WorldDatabase; +extern DatabaseType CharacterDatabase; +extern DatabaseType LoginDatabase; + +#endif + diff --git a/src/server/shared/Database/DatabaseImpl.h b/src/server/shared/Database/DatabaseImpl.h new file mode 100644 index 00000000000..f0ba9c84a30 --- /dev/null +++ b/src/server/shared/Database/DatabaseImpl.h @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "Database/Database.h" +#include "Database/SqlOperations.h" + + +/// Function body definitions for the template function members of the Database class + + +#define ASYNC_QUERY_BODY(sql, queue_itr) \ + if (!sql) return false; \ + \ + QueryQueues::iterator queue_itr; \ + \ + { \ + ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \ + queue_itr = m_queryQueues.find(queryThread); \ + if (queue_itr == m_queryQueues.end()) return false; \ + } + + +#define ASYNC_PQUERY_BODY(format, szQuery) \ + if(!format) return false; \ + \ + char szQuery [MAX_QUERY_LEN]; \ + \ + { \ + va_list ap; \ + \ + va_start(ap, format); \ + int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap ); \ + va_end(ap); \ + \ + if(res==-1) \ + { \ + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); \ + return false; \ + } \ + } + + +#define ASYNC_DELAYHOLDER_BODY(holder, queue_itr) \ + if (!holder) return false; \ + \ + QueryQueues::iterator queue_itr; \ + \ + { \ + ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \ + queue_itr = m_queryQueues.find(queryThread); \ + if (queue_itr == m_queryQueues.end()) return false; \ + } + + +// -- Query / member -- + + +template<class Class> +bool +Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *sql) +{ + ASYNC_QUERY_BODY(sql, itr) + return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class>(object, method), itr->second)); +} + + +template<class Class, typename ParamType1> +bool +Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql) +{ + ASYNC_QUERY_BODY(sql, itr) + return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1>(object, method, (QueryResult_AutoPtr)NULL, param1), itr->second)); +} + + +template<class Class, typename ParamType1, typename ParamType2> +bool +Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql) +{ + ASYNC_QUERY_BODY(sql, itr) + return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2>(object, method, (QueryResult_AutoPtr)NULL, param1, param2), itr->second)); +} + + +template<class Class, typename ParamType1, typename ParamType2, typename ParamType3> +bool +Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql) +{ + ASYNC_QUERY_BODY(sql, itr) + return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2, ParamType3>(object, method, (QueryResult_AutoPtr)NULL, param1, param2, param3), itr->second)); +} + + +// -- Query / static -- + + +template<typename ParamType1> +bool +Database::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *sql) +{ + ASYNC_QUERY_BODY(sql, itr) + return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1>(method, (QueryResult_AutoPtr)NULL, param1), itr->second)); +} + + +template<typename ParamType1, typename ParamType2> +bool +Database::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql) +{ + ASYNC_QUERY_BODY(sql, itr) + return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1, ParamType2>(method, (QueryResult_AutoPtr)NULL, param1, param2), itr->second)); +} + + +template<typename ParamType1, typename ParamType2, typename ParamType3> +bool +Database::AsyncQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql) +{ + ASYNC_QUERY_BODY(sql, itr) + return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1, ParamType2, ParamType3>(method, (QueryResult_AutoPtr)NULL, param1, param2, param3), itr->second)); +} + + +// -- PQuery / member -- + + +template<class Class> +bool +Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr), const char *format,...) +{ + ASYNC_PQUERY_BODY(format, szQuery) + return AsyncQuery(object, method, szQuery); +} + + +template<class Class, typename ParamType1> +bool +Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...) +{ + ASYNC_PQUERY_BODY(format, szQuery) + return AsyncQuery(object, method, param1, szQuery); +} + + +template<class Class, typename ParamType1, typename ParamType2> +bool +Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...) +{ + ASYNC_PQUERY_BODY(format, szQuery) + return AsyncQuery(object, method, param1, param2, szQuery); +} + + +template<class Class, typename ParamType1, typename ParamType2, typename ParamType3> +bool +Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) +{ + ASYNC_PQUERY_BODY(format, szQuery) + return AsyncQuery(object, method, param1, param2, param3, szQuery); +} + + +// -- PQuery / static -- + + +template<typename ParamType1> +bool +Database::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1), ParamType1 param1, const char *format,...) +{ + ASYNC_PQUERY_BODY(format, szQuery) + return AsyncQuery(method, param1, szQuery); +} + + +template<typename ParamType1, typename ParamType2> +bool +Database::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...) +{ + ASYNC_PQUERY_BODY(format, szQuery) + return AsyncQuery(method, param1, param2, szQuery); +} + + +template<typename ParamType1, typename ParamType2, typename ParamType3> +bool +Database::AsyncPQuery(void (*method)(QueryResult_AutoPtr, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...) +{ + ASYNC_PQUERY_BODY(format, szQuery) + return AsyncQuery(method, param1, param2, param3, szQuery); +} + + +// -- QueryHolder -- + + +template<class Class> +bool +Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SqlQueryHolder*), SqlQueryHolder *holder) +{ + ASYNC_DELAYHOLDER_BODY(holder, itr) + return holder->Execute(new Trinity::QueryCallback<Class, SqlQueryHolder*>(object, method, (QueryResult_AutoPtr)NULL, holder), m_threadBody, itr->second); +} + + +template<class Class, typename ParamType1> +bool +Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult_AutoPtr, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1) +{ + ASYNC_DELAYHOLDER_BODY(holder, itr) + return holder->Execute(new Trinity::QueryCallback<Class, SqlQueryHolder*, ParamType1>(object, method, (QueryResult_AutoPtr)NULL, holder, param1), m_threadBody, itr->second); +} + + +#undef ASYNC_QUERY_BODY +#undef ASYNC_PQUERY_BODY +#undef ASYNC_DELAYHOLDER_BODY diff --git a/src/server/shared/Database/Field.cpp b/src/server/shared/Database/Field.cpp new file mode 100644 index 00000000000..191a2884aac --- /dev/null +++ b/src/server/shared/Database/Field.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DatabaseEnv.h" + +Field::Field() : +mValue(NULL), mType(DB_TYPE_UNKNOWN) +{ +} + +Field::Field(Field &f) +{ + const char *value; + + value = f.GetString(); + + if (value) + { + mValue = new char[strlen(value) + 1]; + if (mValue) + strcpy(mValue, value); + } + else + mValue = NULL; + + mType = f.GetType(); +} + +Field::Field(const char *value, enum Field::DataTypes type) : +mType(type) +{ + if (value) + { + mValue = new char[strlen(value) + 1]; + if (mValue) + strcpy(mValue, value); + } + else + mValue = NULL; +} + +Field::~Field() +{ + if (mValue) + delete [] mValue; +} + +void Field::SetValue(const char *value) +{ + if (mValue) + delete [] mValue; + + if (value) + { + mValue = new char[strlen(value) + 1]; + strcpy(mValue, value); + } + else + mValue = NULL; +} diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h new file mode 100644 index 00000000000..8d149858a42 --- /dev/null +++ b/src/server/shared/Database/Field.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(FIELD_H) +#define FIELD_H + +class Field +{ + public: + + enum DataTypes + { + DB_TYPE_UNKNOWN = 0x00, + DB_TYPE_STRING = 0x01, + DB_TYPE_INTEGER = 0x02, + DB_TYPE_FLOAT = 0x03, + DB_TYPE_BOOL = 0x04 + }; + + Field(); + Field(Field &f); + Field(const char *value, enum DataTypes type); + + ~Field(); + + enum DataTypes GetType() const { return mType; } + + const char *GetString() const { return mValue; } + std::string GetCppString() const + { + return mValue ? mValue : ""; // std::string s = 0 have undefine result in C++ + } + float GetFloat() const { return mValue ? static_cast<float>(atof(mValue)) : 0.0f; } + bool GetBool() const { return mValue ? atoi(mValue) > 0 : false; } + int32 GetInt32() const { return mValue ? static_cast<int32>(atol(mValue)) : int32(0); } + uint8 GetUInt8() const { return mValue ? static_cast<uint8>(atol(mValue)) : uint8(0); } + uint16 GetUInt16() const { return mValue ? static_cast<uint16>(atol(mValue)) : uint16(0); } + int16 GetInt16() const { return mValue ? static_cast<int16>(atol(mValue)) : int16(0); } + uint32 GetUInt32() const { return mValue ? static_cast<uint32>(atol(mValue)) : uint32(0); } + uint64 GetUInt64() const + { + if(mValue) + { + uint64 value; + sscanf(mValue,UI64FMTD,&value); + return value; + } + else + return 0; + } + uint64 GetInt64() const + { + if(mValue) + { + int64 value; + sscanf(mValue,SI64FMTD,&value); + return value; + } + else + return 0; + } + + void SetType(enum DataTypes type) { mType = type; } + + void SetValue(const char *value); + + private: + char *mValue; + enum DataTypes mType; +}; +#endif + diff --git a/src/server/shared/Database/QueryResult.cpp b/src/server/shared/Database/QueryResult.cpp new file mode 100644 index 00000000000..8b0c437b066 --- /dev/null +++ b/src/server/shared/Database/QueryResult.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DatabaseEnv.h" + +QueryResult::QueryResult(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) +: mResult(result) +, mFieldCount(fieldCount) +, mRowCount(rowCount) +{ + mCurrentRow = new Field[mFieldCount]; + ASSERT(mCurrentRow); + + for (uint32 i = 0; i < mFieldCount; i++) + mCurrentRow[i].SetType(ConvertNativeType(fields[i].type)); +} + +QueryResult::~QueryResult() +{ + EndQuery(); +} + +bool QueryResult::NextRow() +{ + MYSQL_ROW row; + + if (!mResult) + return false; + + row = mysql_fetch_row(mResult); + if (!row) + { + EndQuery(); + return false; + } + + for (uint32 i = 0; i < mFieldCount; i++) + mCurrentRow[i].SetValue(row[i]); + + return true; +} + +void QueryResult::EndQuery() +{ + if (mCurrentRow) + { + delete [] mCurrentRow; + mCurrentRow = 0; + } + + if (mResult) + { + mysql_free_result(mResult); + mResult = 0; + } +} + +enum Field::DataTypes QueryResult::ConvertNativeType(enum_field_types mysqlType) const +{ + switch (mysqlType) + { + case FIELD_TYPE_TIMESTAMP: + case FIELD_TYPE_DATE: + case FIELD_TYPE_TIME: + case FIELD_TYPE_DATETIME: + case FIELD_TYPE_YEAR: + case FIELD_TYPE_STRING: + case FIELD_TYPE_VAR_STRING: + case FIELD_TYPE_BLOB: + case FIELD_TYPE_SET: + case FIELD_TYPE_NULL: + return Field::DB_TYPE_STRING; + case FIELD_TYPE_TINY: + + case FIELD_TYPE_SHORT: + case FIELD_TYPE_LONG: + case FIELD_TYPE_INT24: + case FIELD_TYPE_LONGLONG: + case FIELD_TYPE_ENUM: + return Field::DB_TYPE_INTEGER; + case FIELD_TYPE_DECIMAL: + case FIELD_TYPE_FLOAT: + case FIELD_TYPE_DOUBLE: + return Field::DB_TYPE_FLOAT; + default: + return Field::DB_TYPE_UNKNOWN; + } +} diff --git a/src/server/shared/Database/QueryResult.h b/src/server/shared/Database/QueryResult.h new file mode 100644 index 00000000000..4eec9915362 --- /dev/null +++ b/src/server/shared/Database/QueryResult.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(QUERYRESULT_H) +#define QUERYRESULT_H + +#include <ace/Refcounted_Auto_Ptr.h> +#include <ace/Null_Mutex.h> + +#include "Field.h" + +#ifdef WIN32 +#define FD_SETSIZE 1024 +#include <winsock2.h> +#include <mysql/mysql.h> +#else +#include <mysql.h> +#endif + +class QueryResult +{ + public: + QueryResult(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount); + ~QueryResult(); + + bool NextRow(); + + Field *Fetch() const { return mCurrentRow; } + + const Field & operator [] (int index) const { return mCurrentRow[index]; } + + uint32 GetFieldCount() const { return mFieldCount; } + uint64 GetRowCount() const { return mRowCount; } + + protected: + Field *mCurrentRow; + uint32 mFieldCount; + uint64 mRowCount; + + private: + enum Field::DataTypes ConvertNativeType(enum_field_types mysqlType) const; + void EndQuery(); + MYSQL_RES *mResult; + +}; + +typedef ACE_Refcounted_Auto_Ptr<QueryResult, ACE_Null_Mutex> QueryResult_AutoPtr; + +typedef std::vector<std::string> QueryFieldNames; + +class QueryNamedResult +{ + public: + explicit QueryNamedResult(QueryResult* query, QueryFieldNames const& names) : mQuery(query), mFieldNames(names) {} + ~QueryNamedResult() { delete mQuery; } + + // compatible interface with QueryResult + bool NextRow() { return mQuery->NextRow(); } + Field *Fetch() const { return mQuery->Fetch(); } + uint32 GetFieldCount() const { return mQuery->GetFieldCount(); } + uint64 GetRowCount() const { return mQuery->GetRowCount(); } + Field const& operator[] (int index) const { return (*mQuery)[index]; } + + // named access + Field const& operator[] (const std::string &name) const { return mQuery->Fetch()[GetField_idx(name)]; } + QueryFieldNames const& GetFieldNames() const { return mFieldNames; } + + uint32 GetField_idx(const std::string &name) const + { + for (size_t idx = 0; idx < mFieldNames.size(); ++idx) + { + if(mFieldNames[idx] == name) + return idx; + } + ASSERT(false && "unknown field name"); + return uint32(-1); + } + + protected: + QueryResult *mQuery; + QueryFieldNames mFieldNames; +}; + +#endif + diff --git a/src/server/shared/Database/SQLStorage.cpp b/src/server/shared/Database/SQLStorage.cpp new file mode 100644 index 00000000000..f42c31b2fea --- /dev/null +++ b/src/server/shared/Database/SQLStorage.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SQLStorage.h" +#include "SQLStorageImpl.h" + +extern Database WorldDatabase; + +const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiisi"; +const char CreatureInfodstfmt[]="iiiiiiiiiisssibbiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifffliiiiiiiliiiii"; +const char CreatureDataAddonInfofmt[]="iiiiiis"; +const char CreatureModelfmt[]="iffbi"; +const char CreatureInfoAddonInfofmt[]="iiiiiis"; +const char EquipmentInfofmt[]="iiii"; +const char GameObjectInfosrcfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisi"; +const char GameObjectInfodstfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"; +const char ItemPrototypesrcfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiisiiiii"; +const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiiii"; +const char PageTextfmt[]="isii"; +const char InstanceTemplatesrcfmt[]="iiiffffsb"; +const char InstanceTemplatedstfmt[]="iiiffffib"; + +SQLStorage sCreatureStorage(CreatureInfosrcfmt, CreatureInfodstfmt, "entry","creature_template"); +SQLStorage sCreatureDataAddonStorage(CreatureDataAddonInfofmt,"guid","creature_addon"); +SQLStorage sCreatureModelStorage(CreatureModelfmt,"modelid","creature_model_info"); +SQLStorage sCreatureInfoAddonStorage(CreatureInfoAddonInfofmt,"entry","creature_template_addon"); +SQLStorage sEquipmentStorage(EquipmentInfofmt,"entry","creature_equip_template"); +SQLStorage sGOStorage(GameObjectInfosrcfmt, GameObjectInfodstfmt, "entry","gameobject_template"); +SQLStorage sItemStorage(ItemPrototypesrcfmt, ItemPrototypedstfmt, "entry","item_template"); +SQLStorage sPageTextStore(PageTextfmt,"entry","page_text"); +SQLStorage sInstanceTemplate(InstanceTemplatesrcfmt, InstanceTemplatedstfmt, "map","instance_template"); + +void SQLStorage::Free () +{ + uint32 offset=0; + for (uint32 x=0; x<iNumFields; x++) + if (dst_format[x]==FT_STRING) + { + for (uint32 y=0; y<MaxEntry; y++) + if(pIndex[y]) + delete [] *(char**)((char*)(pIndex[y])+offset); + + offset += sizeof(char*); + } + else if (dst_format[x]==FT_LOGIC) + offset += sizeof(bool); + else if (dst_format[x]==FT_BYTE) + offset += sizeof(char); + else + offset += 4; + + delete [] pIndex; + delete [] data; +} + +void SQLStorage::Load() +{ + SQLStorageLoader loader; + loader.Load(*this); +} diff --git a/src/server/shared/Database/SQLStorage.h b/src/server/shared/Database/SQLStorage.h new file mode 100644 index 00000000000..931c46b1995 --- /dev/null +++ b/src/server/shared/Database/SQLStorage.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SQLSTORAGE_H +#define SQLSTORAGE_H + +#include "Common.h" +#include "Database/DatabaseEnv.h" + +class SQLStorage +{ + template<class T> + friend struct SQLStorageLoaderBase; + + public: + + SQLStorage(const char* fmt, const char * _entry_field, const char * sqlname) + { + src_format = fmt; + dst_format = fmt; + init(_entry_field, sqlname); + } + + SQLStorage(const char* src_fmt, const char* dst_fmt, const char * _entry_field, const char * sqlname) + { + src_format = src_fmt; + dst_format = dst_fmt; + init(_entry_field, sqlname); + } + + ~SQLStorage() + { + Free(); + } + + template<class T> + T const* LookupEntry(uint32 id) const + { + if( id == 0 ) + return NULL; + if(id >= MaxEntry) + return NULL; + return reinterpret_cast<T const*>(pIndex[id]); + } + + uint32 RecordCount; + uint32 MaxEntry; + uint32 iNumFields; + + char const* GetTableName() const { return table; } + + void Load(); + void Free(); + + private: + void init(const char * _entry_field, const char * sqlname) + { + entry_field = _entry_field; + table=sqlname; + data=NULL; + pIndex=NULL; + iNumFields = strlen(src_format); + MaxEntry = 0; + } + + char** pIndex; + + char *data; + const char *src_format; + const char *dst_format; + const char *table; + const char *entry_field; + //bool HasString; +}; + +template <class T> +struct SQLStorageLoaderBase +{ + public: + void Load(SQLStorage &storage); + + template<class S, class D> + void convert(uint32 field_pos, S src, D &dst); + template<class S> + void convert_to_str(uint32 field_pos, S src, char * & dst); + template<class D> + void convert_from_str(uint32 field_pos, char * src, D& dst); + void convert_str_to_str(uint32 field_pos, char *src, char *&dst); + + private: + template<class V> + void storeValue(V value, SQLStorage &store, char *p, int x, uint32 &offset); + void storeValue(char * value, SQLStorage &store, char *p, int x, uint32 &offset); +}; + +struct SQLStorageLoader : public SQLStorageLoaderBase<SQLStorageLoader> +{ +}; + +#endif + diff --git a/src/server/shared/Database/SQLStorageImpl.h b/src/server/shared/Database/SQLStorageImpl.h new file mode 100644 index 00000000000..c74be48c34c --- /dev/null +++ b/src/server/shared/Database/SQLStorageImpl.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ProgressBar.h" +#include "Log.h" +#include "DBCFileLoader.h" + +template<class T> +template<class S, class D> +void SQLStorageLoaderBase<T>::convert(uint32 /*field_pos*/, S src, D &dst) +{ + dst = D(src); +} + +template<class T> +void SQLStorageLoaderBase<T>::convert_str_to_str(uint32 /*field_pos*/, char *src, char *&dst) +{ + if(!src) + { + dst = new char[1]; + *dst = 0; + } + else + { + uint32 l = strlen(src) + 1; + dst = new char[l]; + memcpy(dst, src, l); + } +} + +template<class T> +template<class S> +void SQLStorageLoaderBase<T>::convert_to_str(uint32 /*field_pos*/, S /*src*/, char * & dst) +{ + dst = new char[1]; + *dst = 0; +} + +template<class T> +template<class D> +void SQLStorageLoaderBase<T>::convert_from_str(uint32 /*field_pos*/, char * /*src*/, D& dst) +{ + dst = 0; +} + +template<class T> +template<class V> +void SQLStorageLoaderBase<T>::storeValue(V value, SQLStorage &store, char *p, int x, uint32 &offset) +{ + T * subclass = (static_cast<T*>(this)); + switch(store.dst_format[x]) + { + case FT_LOGIC: + subclass->convert(x, value, *((bool*)(&p[offset])) ); + offset+=sizeof(bool); + break; + case FT_BYTE: + subclass->convert(x, value, *((char*)(&p[offset])) ); + offset+=sizeof(char); + break; + case FT_INT: + subclass->convert(x, value, *((uint32*)(&p[offset])) ); + offset+=sizeof(uint32); + break; + case FT_FLOAT: + subclass->convert(x, value, *((float*)(&p[offset])) ); + offset+=sizeof(float); + break; + case FT_STRING: + subclass->convert_to_str(x, value, *((char**)(&p[offset])) ); + offset+=sizeof(char*); + break; + } +} + +template<class T> +void SQLStorageLoaderBase<T>::storeValue(char * value, SQLStorage &store, char *p, int x, uint32 &offset) +{ + T * subclass = (static_cast<T*>(this)); + switch(store.dst_format[x]) + { + case FT_LOGIC: + subclass->convert_from_str(x, value, *((bool*)(&p[offset])) ); + offset+=sizeof(bool); + break; + case FT_BYTE: + subclass->convert_from_str(x, value, *((char*)(&p[offset])) ); + offset+=sizeof(char); + break; + case FT_INT: + subclass->convert_from_str(x, value, *((uint32*)(&p[offset])) ); + offset+=sizeof(uint32); + break; + case FT_FLOAT: + subclass->convert_from_str(x, value, *((float*)(&p[offset])) ); + offset+=sizeof(float); + break; + case FT_STRING: + subclass->convert_str_to_str(x, value, *((char**)(&p[offset])) ); + offset+=sizeof(char*); + break; + } +} + +template<class T> +void SQLStorageLoaderBase<T>::Load(SQLStorage &store) +{ + uint32 maxi; + Field *fields; + QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT MAX(%s) FROM %s", store.entry_field, store.table); + if(!result) + { + sLog.outError("Error loading %s table (not exist?)\n", store.table); + exit(1); // Stop server at loading non exited table or not accessable table + } + + maxi = (*result)[0].GetUInt32()+1; + + result = WorldDatabase.PQuery("SELECT COUNT(*) FROM %s", store.table); + if(result) + { + fields = result->Fetch(); + store.RecordCount = fields[0].GetUInt32(); + } + else + store.RecordCount = 0; + + result = WorldDatabase.PQuery("SELECT * FROM %s", store.table); + + if(!result) + { + sLog.outError("%s table is empty!\n", store.table); + store.RecordCount = 0; + return; + } + + uint32 recordsize = 0; + uint32 offset = 0; + + if(store.iNumFields != result->GetFieldCount()) + { + store.RecordCount = 0; + sLog.outError("Error in %s table, probably sql file format was updated (there should be %d fields in sql).\n", store.table, store.iNumFields); + exit(1); // Stop server at loading broken or non-compatible table. + } + + //get struct size + uint32 sc=0; + uint32 bo=0; + uint32 bb=0; + for (uint32 x=0; x< store.iNumFields; x++) + if(store.dst_format[x]==FT_STRING) + ++sc; + else if (store.dst_format[x]==FT_LOGIC) + ++bo; + else if (store.dst_format[x]==FT_BYTE) + ++bb; + recordsize=(store.iNumFields-sc-bo-bb)*4+sc*sizeof(char*)+bo*sizeof(bool)+bb*sizeof(char); + + char** newIndex=new char*[maxi]; + memset(newIndex,0,maxi*sizeof(char*)); + + char * _data= new char[store.RecordCount *recordsize]; + uint32 count=0; + barGoLink bar( store.RecordCount ); + do + { + fields = result->Fetch(); + bar.step(); + char *p=(char*)&_data[recordsize*count]; + newIndex[fields[0].GetUInt32()]=p; + + offset=0; + for (uint32 x = 0; x < store.iNumFields; x++) + switch(store.src_format[x]) + { + case FT_LOGIC: + storeValue((bool)(fields[x].GetUInt32() > 0), store, p, x, offset); break; + case FT_BYTE: + storeValue((char)fields[x].GetUInt8(), store, p, x, offset); break; + case FT_INT: + storeValue((uint32)fields[x].GetUInt32(), store, p, x, offset); break; + case FT_FLOAT: + storeValue((float)fields[x].GetFloat(), store, p, x, offset); break; + case FT_STRING: + storeValue((char*)fields[x].GetString(), store, p, x, offset); break; + } + ++count; + }while( result->NextRow() ); + + store.pIndex = newIndex; + store.MaxEntry = maxi; + store.data = _data; +} + diff --git a/src/server/shared/Database/SqlDelayThread.cpp b/src/server/shared/Database/SqlDelayThread.cpp new file mode 100644 index 00000000000..43de3c63ffc --- /dev/null +++ b/src/server/shared/Database/SqlDelayThread.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Database/SqlDelayThread.h" +#include "Database/SqlOperations.h" +#include "DatabaseEnv.h" + +SqlDelayThread::SqlDelayThread(Database* db) : m_dbEngine(db), m_running(true) +{ +} + +void SqlDelayThread::run() +{ + mysql_thread_init(); + + SqlAsyncTask * s = NULL; + + ACE_Time_Value _time(2); + while (m_running) + { + // if the running state gets turned off while sleeping + // empty the queue before exiting + s = dynamic_cast<SqlAsyncTask*> (m_sqlQueue.dequeue()); + if (s) + { + s->call(); + delete s; + } + } + + mysql_thread_end(); +} + +void SqlDelayThread::Stop() +{ + m_running = false; + m_sqlQueue.queue()->deactivate(); +} + +bool SqlDelayThread::Delay(SqlOperation* sql) +{ + int res = m_sqlQueue.enqueue(new SqlAsyncTask(m_dbEngine, sql)); + return (res != -1); +} diff --git a/src/server/shared/Database/SqlDelayThread.h b/src/server/shared/Database/SqlDelayThread.h new file mode 100644 index 00000000000..d603813c8fa --- /dev/null +++ b/src/server/shared/Database/SqlDelayThread.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SQLDELAYTHREAD_H +#define __SQLDELAYTHREAD_H + +#include "ace/Thread_Mutex.h" +#include "ace/Activation_Queue.h" +#include "Threading.h" + +class Database; +class SqlOperation; + +class SqlDelayThread : public ACE_Based::Runnable +{ + typedef ACE_Activation_Queue SqlQueue; + + private: + SqlQueue m_sqlQueue; ///< Queue of SQL statements + Database* m_dbEngine; ///< Pointer to used Database engine + volatile bool m_running; + + SqlDelayThread(); + public: + SqlDelayThread(Database* db); + + ///< Put sql statement to delay queue + bool Delay(SqlOperation* sql); + + void Stop(); ///< Stop event + virtual void run(); ///< Main Thread loop +}; +#endif //__SQLDELAYTHREAD_H diff --git a/src/server/shared/Database/SqlOperations.cpp b/src/server/shared/Database/SqlOperations.cpp new file mode 100644 index 00000000000..785c5cb84e7 --- /dev/null +++ b/src/server/shared/Database/SqlOperations.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SqlOperations.h" +#include "SqlDelayThread.h" +#include "DatabaseEnv.h" +#include "DatabaseImpl.h" + +/// ---- ASYNC STATEMENTS / TRANSACTIONS ---- + +void SqlStatement::Execute(Database *db) +{ + /// just do it + db->DirectExecute(m_sql); +} + +void SqlTransaction::Execute(Database *db) +{ + const char* sql; + + m_Mutex.acquire(); + if (m_queue.empty()) + { + m_Mutex.release(); + return; + } + + db->DirectExecute("START TRANSACTION"); + while (!m_queue.empty()) + { + sql = m_queue.front(); + + if (!db->DirectExecute(sql)) + { + free((void*)const_cast<char*>(sql)); + m_queue.pop(); + db->DirectExecute("ROLLBACK"); + while (!m_queue.empty()) + { + free((void*)const_cast<char*>(m_queue.front())); + m_queue.pop(); + } + m_Mutex.release(); + return; + } + + free((void*)const_cast<char*>(sql)); + m_queue.pop(); + } + + db->DirectExecute("COMMIT"); + m_Mutex.release(); +} + +/// ---- ASYNC QUERIES ---- + +void SqlQuery::Execute(Database *db) +{ + if (!m_callback || !m_queue) + return; + + /// execute the query and store the result in the callback + m_callback->SetResult(db->Query(m_sql)); + /// add the callback to the sql result queue of the thread it originated from + m_queue->add(m_callback); +} + +void SqlResultQueue::Update() +{ + /// execute the callbacks waiting in the synchronization queue + Trinity::IQueryCallback* callback; + while (next(callback)) + { + callback->Execute(); + delete callback; + } +} + +bool SqlQueryHolder::Execute(Trinity::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue) +{ + if (!callback || !thread || !queue) + return false; + + /// delay the execution of the queries, sync them with the delay thread + /// which will in turn resync on execution (via the queue) and call back + SqlQueryHolderEx *holderEx = new SqlQueryHolderEx(this, callback, queue); + thread->Delay(holderEx); + return true; +} + +bool SqlQueryHolder::SetQuery(size_t index, const char *sql) +{ + if (m_queries.size() <= index) + { + sLog.outError("Query index (%u) out of range (size: %u) for query: %s",index,(uint32)m_queries.size(),sql); + return false; + } + + if (m_queries[index].first != NULL) + { + sLog.outError("Attempt assign query to holder index (%u) where other query stored (Old: [%s] New: [%s])", + index,m_queries[index].first,sql); + return false; + } + + /// not executed yet, just stored (it's not called a holder for nothing) + m_queries[index] = SqlResultPair(strdup(sql), QueryResult_AutoPtr(NULL)); + return true; +} + +bool SqlQueryHolder::SetPQuery(size_t index, const char *format, ...) +{ + if (!format) + { + sLog.outError("Query (index: %u) is empty.",index); + return false; + } + + va_list ap; + char szQuery [MAX_QUERY_LEN]; + va_start(ap, format); + int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap); + va_end(ap); + + if (res==-1) + { + sLog.outError("SQL Query truncated (and not execute) for format: %s",format); + return false; + } + + return SetQuery(index,szQuery); +} + +QueryResult_AutoPtr SqlQueryHolder::GetResult(size_t index) +{ + if (index < m_queries.size()) + { + /// the query strings are freed on the first GetResult or in the destructor + if (m_queries[index].first != NULL) + { + free((void*)(const_cast<char*>(m_queries[index].first))); + m_queries[index].first = NULL; + } + /// when you get a result aways remember to delete it! + return m_queries[index].second; + } + else + return QueryResult_AutoPtr(NULL); +} + +void SqlQueryHolder::SetResult(size_t index, QueryResult_AutoPtr result) +{ + /// store the result in the holder + if (index < m_queries.size()) + m_queries[index].second = result; +} + +SqlQueryHolder::~SqlQueryHolder() +{ + for (size_t i = 0; i < m_queries.size(); i++) + { + /// if the result was never used, free the resources + /// results used already (getresult called) are expected to be deleted + if (m_queries[i].first != NULL) + free((void*)(const_cast<char*>(m_queries[i].first))); + } +} + +void SqlQueryHolder::SetSize(size_t size) +{ + /// to optimize push_back, reserve the number of queries about to be executed + m_queries.resize(size); +} + +void SqlQueryHolderEx::Execute(Database *db) +{ + if (!m_holder || !m_callback || !m_queue) + return; + + /// we can do this, we are friends + std::vector<SqlQueryHolder::SqlResultPair> &queries = m_holder->m_queries; + + for (size_t i = 0; i < queries.size(); i++) + { + /// execute all queries in the holder and pass the results + char const *sql = queries[i].first; + if(sql) m_holder->SetResult(i, db->Query(sql)); + } + + /// sync with the caller thread + m_queue->add(m_callback); +} diff --git a/src/server/shared/Database/SqlOperations.h b/src/server/shared/Database/SqlOperations.h new file mode 100644 index 00000000000..f2e09c0c921 --- /dev/null +++ b/src/server/shared/Database/SqlOperations.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SQLOPERATIONS_H +#define __SQLOPERATIONS_H + +#include "Common.h" + +#include "ace/Thread_Mutex.h" +#include "ace/Method_Request.h" +#include "LockedQueue.h" +#include <queue> +#include "Utilities/Callback.h" +#include "QueryResult.h" + +/// ---- BASE --- + +class Database; +class SqlDelayThread; + +class SqlOperation +{ + public: + virtual void OnRemove() { delete this; } + virtual void Execute(Database *db) = 0; + virtual ~SqlOperation() {} +}; + +/// ---- ASYNC STATEMENTS / TRANSACTIONS ---- + +class SqlStatement : public SqlOperation +{ + private: + const char *m_sql; + public: + SqlStatement(const char *sql) : m_sql(strdup(sql)){} + ~SqlStatement() { void* tofree = const_cast<char*>(m_sql); free(tofree); } + void Execute(Database *db); +}; + +class SqlTransaction : public SqlOperation +{ + private: + std::queue<const char*> m_queue; + ACE_Thread_Mutex m_Mutex; + public: + SqlTransaction() {} + void DelayExecute(const char *sql) + { + m_Mutex.acquire(); + char* _sql = strdup(sql); + if (_sql) + m_queue.push(_sql); + m_Mutex.release(); + } + void Execute(Database *db); +}; + +/// ---- ASYNC QUERIES ---- + +class SqlQuery; /// contains a single async query +class QueryResult; /// the result of one +class SqlResultQueue; /// queue for thread sync +class SqlQueryHolder; /// groups several async quries +class SqlQueryHolderEx; /// points to a holder, added to the delay thread + +class SqlResultQueue : public ACE_Based::LockedQueue<Trinity::IQueryCallback* , ACE_Thread_Mutex> +{ + public: + SqlResultQueue() {} + void Update(); +}; + +class SqlQuery : public SqlOperation +{ + private: + const char *m_sql; + Trinity::IQueryCallback * m_callback; + SqlResultQueue * m_queue; + public: + SqlQuery(const char *sql, Trinity::IQueryCallback * callback, SqlResultQueue * queue) + : m_sql(strdup(sql)), m_callback(callback), m_queue(queue) {} + ~SqlQuery() { void* tofree = const_cast<char*>(m_sql); free(tofree); } + void Execute(Database *db); +}; + +class SqlQueryHolder +{ + friend class SqlQueryHolderEx; + private: + typedef std::pair<const char*, QueryResult_AutoPtr> SqlResultPair; + std::vector<SqlResultPair> m_queries; + public: + SqlQueryHolder() {} + ~SqlQueryHolder(); + bool SetQuery(size_t index, const char *sql); + bool SetPQuery(size_t index, const char *format, ...) ATTR_PRINTF(3,4); + void SetSize(size_t size); + QueryResult_AutoPtr GetResult(size_t index); + void SetResult(size_t index, QueryResult_AutoPtr result); + bool Execute(Trinity::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue); +}; + +class SqlQueryHolderEx : public SqlOperation +{ + private: + SqlQueryHolder * m_holder; + Trinity::IQueryCallback * m_callback; + SqlResultQueue * m_queue; + public: + SqlQueryHolderEx(SqlQueryHolder *holder, Trinity::IQueryCallback * callback, SqlResultQueue * queue) + : m_holder(holder), m_callback(callback), m_queue(queue) {} + void Execute(Database *db); +}; + +class SqlAsyncTask : public ACE_Method_Request +{ +public: + SqlAsyncTask(Database * db, SqlOperation * op) : m_db(db), m_op(op){} + ~SqlAsyncTask() + { + if (!m_op) + return; + + delete m_op; + m_op = NULL; + } + + int call() + { + if (m_db == NULL || m_op == NULL) + return -1; + + try + { + m_op->Execute(m_db); + } + catch(...) + { + return -1; + } + + return 0; + } + +private: + Database * m_db; + SqlOperation * m_op; +}; +#endif //__SQLOPERATIONS_H + diff --git a/src/server/shared/DelayExecutor.cpp b/src/server/shared/DelayExecutor.cpp new file mode 100644 index 00000000000..9a718823232 --- /dev/null +++ b/src/server/shared/DelayExecutor.cpp @@ -0,0 +1,111 @@ +#include <ace/Singleton.h> +#include <ace/Thread_Mutex.h> +#include <ace/Log_Msg.h> + +#include "DelayExecutor.h" + +DelayExecutor* DelayExecutor::instance() +{ + return ACE_Singleton<DelayExecutor, ACE_Thread_Mutex>::instance(); +} + +DelayExecutor::DelayExecutor() + : activated_(false), pre_svc_hook_(0), post_svc_hook_(0) +{ +} + +DelayExecutor::~DelayExecutor() +{ + if (pre_svc_hook_) + delete pre_svc_hook_; + + if (post_svc_hook_) + delete post_svc_hook_; + + deactivate(); +} + +int DelayExecutor::deactivate() +{ + if (!activated()) + return -1; + + activated(false); + queue_.queue()->deactivate(); + wait(); + + return 0; +} + +int DelayExecutor::svc() +{ + if (pre_svc_hook_) + pre_svc_hook_->call(); + + for (;;) + { + ACE_Method_Request* rq = queue_.dequeue(); + + if (!rq) + break; + + rq->call(); + delete rq; + } + + if (post_svc_hook_) + post_svc_hook_->call(); + + return 0; +} + +int DelayExecutor::activate(int num_threads, ACE_Method_Request* pre_svc_hook, ACE_Method_Request* post_svc_hook) +{ + if (activated()) + return -1; + + if (num_threads < 1) + return -1; + + if (pre_svc_hook_) + delete pre_svc_hook_; + + if (post_svc_hook_) + delete post_svc_hook_; + + pre_svc_hook_ = pre_svc_hook; + post_svc_hook_ = post_svc_hook; + + queue_.queue()->activate(); + + if (ACE_Task_Base::activate(THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, num_threads) == -1) + return -1; + + activated(true); + + return true; +} + +int DelayExecutor::execute(ACE_Method_Request* new_req) +{ + if (new_req == NULL) + return -1; + + if (queue_.enqueue(new_req, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) + { + delete new_req; + ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%t) %p\n"), ACE_TEXT("DelayExecutor::execute enqueue")), -1); + } + + return 0; +} + +bool DelayExecutor::activated() +{ + return activated_; +} + +void DelayExecutor::activated(bool s) +{ + activated_ = s; +} diff --git a/src/server/shared/DelayExecutor.h b/src/server/shared/DelayExecutor.h new file mode 100644 index 00000000000..664d8ca78a2 --- /dev/null +++ b/src/server/shared/DelayExecutor.h @@ -0,0 +1,37 @@ +#ifndef _M_DELAY_EXECUTOR_H +#define _M_DELAY_EXECUTOR_H + +#include <ace/Task.h> +#include <ace/Activation_Queue.h> +#include <ace/Method_Request.h> + +class DelayExecutor : protected ACE_Task_Base +{ + public: + + DelayExecutor(); + virtual ~DelayExecutor(); + + static DelayExecutor* instance(); + + int execute(ACE_Method_Request* new_req); + + int activate(int num_threads = 1, ACE_Method_Request* pre_svc_hook = NULL, ACE_Method_Request* post_svc_hook = NULL); + + int deactivate(); + + bool activated(); + + virtual int svc(); + + private: + + ACE_Activation_Queue queue_; + ACE_Method_Request* pre_svc_hook_; + ACE_Method_Request* post_svc_hook_; + bool activated_; + + void activated(bool s); +}; + +#endif // _M_DELAY_EXECUTOR_H diff --git a/src/server/shared/Errors.h b/src/server/shared/Errors.h new file mode 100644 index 00000000000..15c6b1414ed --- /dev/null +++ b/src/server/shared/Errors.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_ERRORS_H +#define TRINITYCORE_ERRORS_H + +#include "Common.h" + +#if PLATFORM != PLATFORM_WINDOWS +#ifndef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#ifdef HAVE_ACE_STACK_TRACE_H +#include "ace/Stack_Trace.h" +#endif + +#ifdef HAVE_ACE_STACK_TRACE_H // old versions ACE not have Stack_Trace.h but used at some oS for better compatibility +#define WPAssert( assertion ) { if (!(assertion)) { ACE_Stack_Trace st; fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__,__FUNCTION__, #assertion, st.c_str()); assert( #assertion &&0 ); } } +#else +#define WPAssert( assertion ) { if (!(assertion)) { fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED2:\n %s\n", __FILE__, __LINE__,__FUNCTION__, #assertion); assert( #assertion &&0 ); } } +#endif +#define WPError( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); assert( false ); } +#define WPWarning( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); } + +#define WPFatal( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); assert( #assertion &&0 ); abort(); } + +#define ASSERT WPAssert +#endif + diff --git a/src/server/shared/LockedQueue.h b/src/server/shared/LockedQueue.h new file mode 100644 index 00000000000..9f8afae6c14 --- /dev/null +++ b/src/server/shared/LockedQueue.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LOCKEDQUEUE_H +#define LOCKEDQUEUE_H + +#include <ace/Guard_T.h> +#include <ace/Thread_Mutex.h> +#include <deque> +#include <assert.h> +#include "Errors.h" + +namespace ACE_Based +{ + template <class T, class LockType, typename StorageType=std::deque<T> > + class LockedQueue + { + //! Lock access to the queue. + LockType _lock; + + //! Storage backing the queue. + StorageType _queue; + + //! Cancellation flag. + volatile bool _canceled; + + public: + + //! Create a LockedQueue. + LockedQueue() + : _canceled(false) + { + } + + //! Destroy a LockedQueue. + virtual ~LockedQueue() + { + } + + //! Adds an item to the queue. + void add(const T& item) + { + lock(); + + //ASSERT(!this->_canceled); + // throw Cancellation_Exception(); + + _queue.push_back(item); + + unlock(); + } + + //! Gets the next result in the queue, if any. + bool next(T& result) + { + // ACE_Guard<LockType> g(this->_lock); + ACE_GUARD_RETURN (LockType, g, this->_lock, false); + + if (_queue.empty()) + return false; + + //ASSERT (!_queue.empty() || !this->_canceled); + // throw Cancellation_Exception(); + result = _queue.front(); + _queue.pop_front(); + + return true; + } + + //! Peeks at the top of the queue. Remember to unlock after use. + T& peek() + { + lock(); + + T& result = _queue.front(); + + return result; + } + + //! Cancels the queue. + void cancel() + { + lock(); + + _canceled = true; + + unlock(); + } + + //! Checks if the queue is cancelled. + bool cancelled() + { + ACE_Guard<LockType> g(this->_lock); + return _canceled; + } + + //! Locks the queue for access. + void lock() + { + this->_lock.acquire(); + } + + //! Unlocks the queue. + void unlock() + { + this->_lock.release(); + } + + ///! Calls pop_front of the queue + void pop_front() + { + ACE_GUARD (LockType, g, this->_lock); + _queue.pop_front(); + } + + ///! Checks if we're empty or not with locks held + bool empty() + { + ACE_GUARD_RETURN (LockType, g, this->_lock, false); + return _queue.empty(); + } + }; +} +#endif diff --git a/src/server/shared/Log.cpp b/src/server/shared/Log.cpp new file mode 100644 index 00000000000..187b9eaa79b --- /dev/null +++ b/src/server/shared/Log.cpp @@ -0,0 +1,1005 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Log.h" +#include "Policies/SingletonImp.h" +#include "Config/ConfigEnv.h" +#include "Util.h" + +#include <stdarg.h> +#include <stdio.h> + +INSTANTIATE_SINGLETON_1( Log ); + +Log::Log() : + raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL), + dberLogfile(NULL), chatLogfile(NULL), m_gmlog_per_account(false), + m_enableLogDBLater(false), m_enableLogDB(false), m_colored(false), + arenaLogFile(NULL) +{ + Initialize(); +} + +Log::~Log() +{ + if( logfile != NULL ) + fclose(logfile); + logfile = NULL; + + if( gmLogfile != NULL ) + fclose(gmLogfile); + gmLogfile = NULL; + + if (charLogfile != NULL) + fclose(charLogfile); + charLogfile = NULL; + + if( dberLogfile != NULL ) + fclose(dberLogfile); + dberLogfile = NULL; + + if (raLogfile != NULL) + fclose(raLogfile); + raLogfile = NULL; + + if (chatLogfile != NULL) + fclose(chatLogfile); + chatLogfile = NULL; + + if (arenaLogFile != NULL) + fclose(arenaLogFile); + arenaLogFile = NULL; +} + +void Log::SetLogLevel(char *Level) +{ + int32 NewLevel =atoi((char*)Level); + if ( NewLevel <0 ) + NewLevel = 0; + m_logLevel = NewLevel; + + outString( "LogLevel is %u",m_logLevel ); +} + +void Log::SetLogFileLevel(char *Level) +{ + int32 NewLevel =atoi((char*)Level); + if ( NewLevel <0 ) + NewLevel = 0; + m_logFileLevel = NewLevel; + + outString( "LogFileLevel is %u",m_logFileLevel ); +} + +void Log::SetDBLogLevel(char *Level) +{ + int32 NewLevel = atoi((char*)Level); + if ( NewLevel < 0 ) + NewLevel = 0; + m_dbLogLevel = NewLevel; + + outString( "DBLogLevel is %u",m_dbLogLevel ); +} + +void Log::Initialize() +{ + /// Check whether we'll log GM commands/RA events/character outputs/chat stuffs + m_dbChar = sConfig.GetBoolDefault("LogDB.Char", false); + m_dbRA = sConfig.GetBoolDefault("LogDB.RA", false); + m_dbGM = sConfig.GetBoolDefault("LogDB.GM", false); + m_dbChat = sConfig.GetBoolDefault("LogDB.Chat", false); + + /// Realm must be 0 by default + SetRealmID(0); + + /// Common log files data + m_logsDir = sConfig.GetStringDefault("LogsDir",""); + if (!m_logsDir.empty()) + if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\')) + m_logsDir.append("/"); + + m_logsTimestamp = "_" + GetTimestampStr(); + + /// Open specific log files + logfile = openLogFile("LogFile","LogTimestamp","w"); + InitColors(sConfig.GetStringDefault("LogColors", "")); + + m_gmlog_per_account = sConfig.GetBoolDefault("GmLogPerAccount",false); + if(!m_gmlog_per_account) + gmLogfile = openLogFile("GMLogFile","GmLogTimestamp","a"); + else + { + // GM log settings for per account case + m_gmlog_filename_format = sConfig.GetStringDefault("GMLogFile", ""); + if(!m_gmlog_filename_format.empty()) + { + bool m_gmlog_timestamp = sConfig.GetBoolDefault("GmLogTimestamp",false); + + size_t dot_pos = m_gmlog_filename_format.find_last_of("."); + if(dot_pos!=m_gmlog_filename_format.npos) + { + if(m_gmlog_timestamp) + m_gmlog_filename_format.insert(dot_pos,m_logsTimestamp); + + m_gmlog_filename_format.insert(dot_pos,"_#%u"); + } + else + { + m_gmlog_filename_format += "_#%u"; + + if(m_gmlog_timestamp) + m_gmlog_filename_format += m_logsTimestamp; + } + + m_gmlog_filename_format = m_logsDir + m_gmlog_filename_format; + } + } + + charLogfile = openLogFile("CharLogFile","CharLogTimestamp","a"); + + dberLogfile = openLogFile("DBErrorLogFile",NULL,"a"); + raLogfile = openLogFile("RaLogFile",NULL,"a"); + chatLogfile = openLogFile("ChatLogFile","ChatLogTimestamp","a"); + arenaLogFile = openLogFile("ArenaLogFile",NULL,"a"); + + // Main log file settings + m_logLevel = sConfig.GetIntDefault("LogLevel", LOGL_NORMAL); + m_logFileLevel = sConfig.GetIntDefault("LogFileLevel", LOGL_NORMAL); + m_dbLogLevel = sConfig.GetIntDefault("DBLogLevel", LOGL_NORMAL); + + m_logFilter = 0; + + if(sConfig.GetBoolDefault("LogFilter_TransportMoves", true)) + m_logFilter |= LOG_FILTER_TRANSPORT_MOVES; + if(sConfig.GetBoolDefault("LogFilter_CreatureMoves", true)) + m_logFilter |= LOG_FILTER_CREATURE_MOVES; + if(sConfig.GetBoolDefault("LogFilter_VisibilityChanges", true)) + m_logFilter |= LOG_FILTER_VISIBILITY_CHANGES; + if(sConfig.GetBoolDefault("LogFilter_AchievementUpdates", true)) + m_logFilter |= LOG_FILTER_ACHIEVEMENT_UPDATES; + + // Char log settings + m_charLog_Dump = sConfig.GetBoolDefault("CharLogDump", false); + m_charLog_Dump_Separate = sConfig.GetBoolDefault("CharLogDump.Separate", false); + if (m_charLog_Dump_Separate) + { + m_dumpsDir = sConfig.GetStringDefault("CharLogDump.SeparateDir", ""); + if (!m_dumpsDir.empty()) + if ((m_dumpsDir.at(m_dumpsDir.length() - 1) != '/') && (m_dumpsDir.at(m_dumpsDir.length() - 1) != '\\')) + m_dumpsDir.append("/"); + } +} + +FILE* Log::openLogFile(char const* configFileName,char const* configTimeStampFlag, char const* mode) +{ + std::string logfn=sConfig.GetStringDefault(configFileName, ""); + if(logfn.empty()) + return NULL; + + if(configTimeStampFlag && sConfig.GetBoolDefault(configTimeStampFlag,false)) + { + size_t dot_pos = logfn.find_last_of("."); + if(dot_pos!=logfn.npos) + logfn.insert(dot_pos,m_logsTimestamp); + else + logfn += m_logsTimestamp; + } + + return fopen((m_logsDir+logfn).c_str(), mode); +} + +FILE* Log::openGmlogPerAccount(uint32 account) +{ + if(m_gmlog_filename_format.empty()) + return NULL; + + char namebuf[TRINITY_PATH_MAX]; + snprintf(namebuf,TRINITY_PATH_MAX,m_gmlog_filename_format.c_str(),account); + return fopen(namebuf, "a"); +} + +void Log::outTimestamp(FILE* file) +{ + time_t t = time(NULL); + tm* aTm = localtime(&t); + // YYYY year + // MM month (2 digits 01-12) + // DD day (2 digits 01-31) + // HH hour (2 digits 00-23) + // MM minutes (2 digits 00-59) + // SS seconds (2 digits 00-59) + fprintf(file,"%-4d-%02d-%02d %02d:%02d:%02d ",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec); +} + +void Log::InitColors(const std::string& str) +{ + if(str.empty()) + { + m_colored = false; + return; + } + + int color[4]; + + std::istringstream ss(str); + + for (uint8 i = 0; i < LogLevels; ++i) + { + ss >> color[i]; + + if(!ss) + return; + + if(color[i] < 0 || color[i] >= Colors) + return; + } + + for (uint8 i = 0; i < LogLevels; ++i) + m_colors[i] = ColorTypes(color[i]); + + m_colored = true; +} + +void Log::SetColor(bool stdout_stream, ColorTypes color) +{ + #if PLATFORM == PLATFORM_WINDOWS + static WORD WinColorFG[Colors] = + { + 0, // BLACK + FOREGROUND_RED, // RED + FOREGROUND_GREEN, // GREEN + FOREGROUND_RED | FOREGROUND_GREEN, // BROWN + FOREGROUND_BLUE, // BLUE + FOREGROUND_RED | FOREGROUND_BLUE,// MAGENTA + FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,// WHITE + // YELLOW + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, + // RED_BOLD + FOREGROUND_RED | FOREGROUND_INTENSITY, + // GREEN_BOLD + FOREGROUND_GREEN | FOREGROUND_INTENSITY, + FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD + // MAGENTA_BOLD + FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + // CYAN_BOLD + FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + // WHITE_BOLD + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY + }; + + HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE ); + SetConsoleTextAttribute(hConsole, WinColorFG[color]); + #else + enum ANSITextAttr + { + TA_NORMAL=0, + TA_BOLD=1, + TA_BLINK=5, + TA_REVERSE=7 + }; + + enum ANSIFgTextAttr + { + FG_BLACK=30, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, + FG_MAGENTA, FG_CYAN, FG_WHITE, FG_YELLOW + }; + + enum ANSIBgTextAttr + { + BG_BLACK=40, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, + BG_MAGENTA, BG_CYAN, BG_WHITE + }; + + static uint8 UnixColorFG[Colors] = + { + FG_BLACK, // BLACK + FG_RED, // RED + FG_GREEN, // GREEN + FG_BROWN, // BROWN + FG_BLUE, // BLUE + FG_MAGENTA, // MAGENTA + FG_CYAN, // CYAN + FG_WHITE, // WHITE + FG_YELLOW, // YELLOW + FG_RED, // LRED + FG_GREEN, // LGREEN + FG_BLUE, // LBLUE + FG_MAGENTA, // LMAGENTA + FG_CYAN, // LCYAN + FG_WHITE // LWHITE + }; + + fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < Colors ? ";1" : "")); + #endif +} + +void Log::ResetColor(bool stdout_stream) +{ + #if PLATFORM == PLATFORM_WINDOWS + HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE ); + SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ); + #else + fprintf(( stdout_stream ? stdout : stderr ), "\x1b[0m"); + #endif +} + +std::string Log::GetTimestampStr() +{ + time_t t = time(NULL); + tm* aTm = localtime(&t); + // YYYY year + // MM month (2 digits 01-12) + // DD day (2 digits 01-31) + // HH hour (2 digits 00-23) + // MM minutes (2 digits 00-59) + // SS seconds (2 digits 00-59) + char buf[20]; + snprintf(buf,20,"%04d-%02d-%02d_%02d-%02d-%02d",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec); + return std::string(buf); +} + +void Log::outDB(LogTypes type, const char * str) +{ + if (!str || type >= MAX_LOG_TYPES) + return; + + std::string new_str(str); + if (new_str.empty()) + return; + LoginDatabase.escape_string(new_str); + + LoginDatabase.PExecute("INSERT INTO logs (time, realm, type, string) " + "VALUES (" UI64FMTD ", %u, %u, '%s');", uint64(time(0)), realm, type, new_str.c_str()); +} + +void Log::outString(const char * str, ...) +{ + if (!str) + return; + + if (m_enableLogDB) + { + // we don't want empty strings in the DB + std::string s(str); + if (s.empty() || s == " ") + return; + + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_STRING, nnew_str); + va_end(ap2); + } + + if (m_colored) + SetColor(true,m_colors[LOGL_NORMAL]); + + va_list ap; + + va_start(ap, str); + vutf8printf(stdout, str, &ap); + va_end(ap); + + if (m_colored) + ResetColor(true); + + printf("\n"); + if(logfile) + { + outTimestamp(logfile); + va_start(ap, str); + vfprintf(logfile, str, ap); + fprintf(logfile, "\n"); + va_end(ap); + + fflush(logfile); + } + fflush(stdout); +} + +void Log::outString() +{ + printf("\n"); + if (logfile) + { + outTimestamp(logfile); + fprintf(logfile, "\n"); + fflush(logfile); + } + fflush(stdout); +} + +void Log::outCrash(const char * err, ...) +{ + if (!err) + return; + + if (m_enableLogDB) + { + va_list ap2; + va_start(ap2, err); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, err, ap2); + outDB(LOG_TYPE_CRASH, nnew_str); + va_end(ap2); + } + + if (m_colored) + SetColor(false,LRED); + + va_list ap; + + va_start(ap, err); + vutf8printf(stdout, err, &ap); + va_end(ap); + + if (m_colored) + ResetColor(false); + + fprintf(stderr, "\n"); + if (logfile) + { + outTimestamp(logfile); + fprintf(logfile, "CRASH ALERT: "); + + va_start(ap, err); + vfprintf(logfile, err, ap); + va_end(ap); + + fprintf(logfile, "\n"); + fflush(logfile); + } + fflush(stderr); +} + +void Log::outError(const char * err, ...) +{ + if (!err) + return; + + if (m_enableLogDB) + { + va_list ap2; + va_start(ap2, err); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, err, ap2); + outDB(LOG_TYPE_ERROR, nnew_str); + va_end(ap2); + } + + if (m_colored) + SetColor(false,LRED); + + va_list ap; + + va_start(ap, err); + vutf8printf(stderr, err, &ap); + va_end(ap); + + if (m_colored) + ResetColor(false); + + fprintf( stderr, "\n"); + if (logfile) + { + outTimestamp(logfile); + fprintf(logfile, "ERROR: "); + + va_start(ap, err); + vfprintf(logfile, err, ap); + va_end(ap); + + fprintf(logfile, "\n"); + fflush(logfile); + } + fflush(stderr); +} + +void Log::outArena(const char * str, ...) +{ + if (!str) + return; + + if (arenaLogFile) + { + va_list ap; + outTimestamp(arenaLogFile); + va_start(ap, str); + vfprintf(arenaLogFile, str, ap); + fprintf(arenaLogFile, "\n"); + va_end(ap); + fflush(arenaLogFile); + } + fflush(stdout); +} + +void Log::outErrorDb(const char * err, ...) +{ + if (!err) + return; + + if (m_colored) + SetColor(false,LRED); + + va_list ap; + + va_start(ap, err); + vutf8printf(stderr, err, &ap); + va_end(ap); + + if (m_colored) + ResetColor(false); + + fprintf( stderr, "\n" ); + + if (logfile) + { + outTimestamp(logfile); + fprintf(logfile, "ERROR: " ); + + va_start(ap, err); + vfprintf(logfile, err, ap); + va_end(ap); + + fprintf(logfile, "\n" ); + fflush(logfile); + } + + if (dberLogfile) + { + outTimestamp(dberLogfile); + va_start(ap, err); + vfprintf(dberLogfile, err, ap); + va_end(ap); + + fprintf(dberLogfile, "\n" ); + fflush(dberLogfile); + } + fflush(stderr); +} + +void Log::outBasic(const char * str, ...) +{ + if (!str) + return; + + if (m_enableLogDB && m_dbLogLevel > LOGL_NORMAL) + { + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_BASIC, nnew_str); + va_end(ap2); + } + + if (m_logLevel > LOGL_NORMAL) + { + if (m_colored) + SetColor(true,m_colors[LOGL_BASIC]); + + va_list ap; + va_start(ap, str); + vutf8printf(stdout, str, &ap); + va_end(ap); + + if (m_colored) + ResetColor(true); + + printf("\n"); + + if (logfile) + { + outTimestamp(logfile); + va_list ap; + va_start(ap, str); + vfprintf(logfile, str, ap); + fprintf(logfile, "\n" ); + va_end(ap); + fflush(logfile); + } + } + fflush(stdout); +} + +void Log::outDetail(const char * str, ...) +{ + if (!str) + return; + + if (m_enableLogDB && m_dbLogLevel > LOGL_BASIC) + { + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_DETAIL, nnew_str); + va_end(ap2); + } + + if (m_logLevel > LOGL_BASIC) + { + if (m_colored) + SetColor(true,m_colors[LOGL_DETAIL]); + + va_list ap; + va_start(ap, str); + vutf8printf(stdout, str, &ap); + va_end(ap); + + if (m_colored) + ResetColor(true); + + printf("\n"); + + if (logfile) + { + outTimestamp(logfile); + va_list ap; + va_start(ap, str); + vfprintf(logfile, str, ap); + va_end(ap); + + fprintf(logfile, "\n"); + fflush(logfile); + } + } + + fflush(stdout); +} + +void Log::outDebugInLine(const char * str, ...) +{ + if (!str) + return; + + if (m_logLevel > LOGL_DETAIL) + { + va_list ap; + va_start(ap, str); + vutf8printf(stdout, str, &ap); + va_end(ap); + + //if(m_colored) + // ResetColor(true); + + if (logfile) + { + va_list ap; + va_start(ap, str); + vfprintf(logfile, str, ap); + va_end(ap); + } + } +} + +void Log::outDebug(const char * str, ...) +{ + if (!str) + return; + + if (m_enableLogDB && m_dbLogLevel > LOGL_DETAIL) + { + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_DEBUG, nnew_str); + va_end(ap2); + } + + if( m_logLevel > LOGL_DETAIL ) + { + if (m_colored) + SetColor(true,m_colors[LOGL_DEBUG]); + + va_list ap; + va_start(ap, str); + vutf8printf(stdout, str, &ap); + va_end(ap); + + if(m_colored) + ResetColor(true); + + printf( "\n" ); + + if (logfile) + { + outTimestamp(logfile); + va_list ap; + va_start(ap, str); + vfprintf(logfile, str, ap); + va_end(ap); + + fprintf(logfile, "\n" ); + fflush(logfile); + } + } + fflush(stdout); +} + +void Log::outStringInLine(const char * str, ...) +{ + if (!str) + return; + + va_list ap; + + va_start(ap, str); + vutf8printf(stdout, str, &ap); + va_end(ap); + + if (logfile) + { + va_start(ap, str); + vfprintf(logfile, str, ap); + va_end(ap); + } +} + +void Log::outCommand(uint32 account, const char * str, ...) +{ + if (!str) + return; + + // TODO: support accountid + if (m_enableLogDB && m_dbGM) + { + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_GM, nnew_str); + va_end(ap2); + } + + if (m_logLevel > LOGL_NORMAL) + { + if (m_colored) + SetColor(true,m_colors[LOGL_BASIC]); + + va_list ap; + va_start(ap, str); + vutf8printf(stdout, str, &ap); + va_end(ap); + + if (m_colored) + ResetColor(true); + + printf("\n"); + + if (logfile) + { + outTimestamp(logfile); + va_list ap; + va_start(ap, str); + vfprintf(logfile, str, ap); + fprintf(logfile, "\n" ); + va_end(ap); + fflush(logfile); + } + } + + if (m_gmlog_per_account) + { + if (FILE* per_file = openGmlogPerAccount (account)) + { + outTimestamp(per_file); + va_list ap; + va_start(ap, str); + vfprintf(per_file, str, ap); + fprintf(per_file, "\n" ); + va_end(ap); + fclose(per_file); + } + } + else if (gmLogfile) + { + outTimestamp(gmLogfile); + va_list ap; + va_start(ap, str); + vfprintf(gmLogfile, str, ap); + fprintf(gmLogfile, "\n" ); + va_end(ap); + fflush(gmLogfile); + } + + fflush(stdout); +} + +void Log::outChar(const char * str, ...) +{ + if (!str) + return; + + if (m_enableLogDB && m_dbChar) + { + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_CHAR, nnew_str); + va_end(ap2); + } + + if (charLogfile) + { + outTimestamp(charLogfile); + va_list ap; + va_start(ap, str); + vfprintf(charLogfile, str, ap); + fprintf(charLogfile, "\n" ); + va_end(ap); + fflush(charLogfile); + } +} + +void Log::outCharDump(const char * str, uint32 account_id, uint32 guid, const char * name) +{ + FILE *file = NULL; + if (m_charLog_Dump_Separate) + { + char fileName[29]; // Max length: name(12) + guid(11) + _.log (5) + \0 + snprintf(fileName, 29, "%d_%s.log", guid, name); + std::string sFileName(m_dumpsDir); + sFileName.append(fileName); + file = fopen((m_logsDir + sFileName).c_str(), "w"); + } + else + file = charLogfile; + if (file) + { + fprintf(file, "== START DUMP == (account: %u guid: %u name: %s )\n%s\n== END DUMP ==\n", + account_id, guid, name, str); + fflush(file); + if (m_charLog_Dump_Separate) + fclose(file); + } +} + +void Log::outRemote(const char * str, ...) +{ + if (!str) + return; + + if (m_enableLogDB && m_dbRA) + { + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_RA, nnew_str); + va_end(ap2); + } + + if (raLogfile) + { + outTimestamp(raLogfile); + va_list ap; + va_start(ap, str); + vfprintf(raLogfile, str, ap); + fprintf(raLogfile, "\n" ); + va_end(ap); + fflush(raLogfile); + } + fflush(stdout); +} + +void Log::outChat(const char * str, ...) +{ + if (!str) + return; + + if (m_enableLogDB && m_dbChat) + { + va_list ap2; + va_start(ap2, str); + char nnew_str[MAX_QUERY_LEN]; + vsnprintf(nnew_str, MAX_QUERY_LEN, str, ap2); + outDB(LOG_TYPE_CHAT, nnew_str); + va_end(ap2); + } + + if (chatLogfile) + { + outTimestamp(chatLogfile); + va_list ap; + va_start(ap, str); + vfprintf(chatLogfile, str, ap); + fprintf(chatLogfile, "\n" ); + fflush(chatLogfile); + va_end(ap); + } + fflush(stdout); +} + +void outstring_log(const char * str, ...) +{ + if (!str) + return; + + char buf[256]; + va_list ap; + va_start(ap, str); + vsnprintf(buf,256, str, ap); + va_end(ap); + + Trinity::Singleton<Log>::Instance().outString(buf); +} + +void detail_log(const char * str, ...) +{ + if (!str) + return; + + char buf[256]; + va_list ap; + va_start(ap, str); + vsnprintf(buf,256, str, ap); + va_end(ap); + + Trinity::Singleton<Log>::Instance().outDetail(buf); +} + +void debug_log(const char * str, ...) +{ + if (!str) + return; + + char buf[256]; + va_list ap; + va_start(ap, str); + vsnprintf(buf,256, str, ap); + va_end(ap); + + Trinity::Singleton<Log>::Instance().outDebug(buf); +} + +void error_log(const char * str, ...) +{ + if (!str) + return; + + char buf[256]; + va_list ap; + va_start(ap, str); + vsnprintf(buf,256, str, ap); + va_end(ap); + + Trinity::Singleton<Log>::Instance().outError(buf); +} + +void error_db_log(const char * str, ...) +{ + if (!str) + return; + + char buf[256]; + va_list ap; + va_start(ap, str); + vsnprintf(buf,256, str, ap); + va_end(ap); + + Trinity::Singleton<Log>::Instance().outErrorDb(buf); +} + diff --git a/src/server/shared/Log.h b/src/server/shared/Log.h new file mode 100644 index 00000000000..deb6c55e4e0 --- /dev/null +++ b/src/server/shared/Log.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_LOG_H +#define TRINITYCORE_LOG_H + +#include "Common.h" +#include "Policies/Singleton.h" +#include "Database/DatabaseEnv.h" + +class Config; + +enum LogFilters +{ + LOG_FILTER_TRANSPORT_MOVES = 1, + LOG_FILTER_CREATURE_MOVES = 2, + LOG_FILTER_VISIBILITY_CHANGES = 4, + LOG_FILTER_ACHIEVEMENT_UPDATES = 8 +}; + +enum LogTypes +{ + LOG_TYPE_STRING = 0, + LOG_TYPE_ERROR = 1, + LOG_TYPE_BASIC = 2, + LOG_TYPE_DETAIL = 3, + LOG_TYPE_DEBUG = 4, + LOG_TYPE_CHAR = 5, + LOG_TYPE_WORLD = 6, + LOG_TYPE_RA = 7, + LOG_TYPE_GM = 8, + LOG_TYPE_CRASH = 9, + LOG_TYPE_CHAT = 10, + MAX_LOG_TYPES +}; + +enum LogLevel +{ + LOGL_NORMAL = 0, + LOGL_BASIC, + LOGL_DETAIL, + LOGL_DEBUG +}; + +const int LogLevels = int(LOGL_DEBUG)+1; + +enum ColorTypes +{ + BLACK, + RED, + GREEN, + BROWN, + BLUE, + MAGENTA, + CYAN, + GREY, + YELLOW, + LRED, + LGREEN, + LBLUE, + LMAGENTA, + LCYAN, + WHITE +}; + +const int Colors = int(WHITE)+1; + +class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ACE_Thread_Mutex> > +{ + friend class Trinity::OperatorNew<Log>; + Log(); + ~Log(); + + public: + void Initialize(); + + void InitColors(const std::string& init_str); + void SetColor(bool stdout_stream, ColorTypes color); + void ResetColor(bool stdout_stream); + + void outDB( LogTypes type, const char * str ); + void outString( const char * str, ... ) ATTR_PRINTF(2,3); + void outString( ); + void outStringInLine( const char * str, ... ) ATTR_PRINTF(2,3); + void outError( const char * err, ... ) ATTR_PRINTF(2,3); + void outCrash( const char * err, ... ) ATTR_PRINTF(2,3); + void outBasic( const char * str, ... ) ATTR_PRINTF(2,3); + void outDetail( const char * str, ... ) ATTR_PRINTF(2,3); + void outDebug( const char * str, ... ) ATTR_PRINTF(2,3); + void outDebugInLine( const char * str, ... ) ATTR_PRINTF(2,3); + void outErrorDb( const char * str, ... ) ATTR_PRINTF(2,3); + void outChar( const char * str, ... ) ATTR_PRINTF(2,3); + void outCommand( uint32 account, const char * str, ...) ATTR_PRINTF(3,4); + void outRemote( const char * str, ... ) ATTR_PRINTF(2,3); + void outChat( const char * str, ... ) ATTR_PRINTF(2,3); + void outArena( const char * str, ... ) ATTR_PRINTF(2,3); + void outCharDump( const char * str, uint32 account_id, uint32 guid, const char * name ); + + static void outTimestamp(FILE* file); + static std::string GetTimestampStr(); + + void SetLogLevel(char * Level); + void SetLogFileLevel(char * Level); + void SetDBLogLevel(char * Level); + void SetRealmID(uint32 id) { realm = id; } + + uint32 getLogFilter() const { return m_logFilter; } + bool IsOutDebug() const { return m_logLevel > 2 || (m_logFileLevel > 2 && logfile); } + bool IsOutCharDump() const { return m_charLog_Dump; } + + bool GetLogDB() { return m_enableLogDB; } + bool GetLogDBLater() { return m_enableLogDBLater; } + void SetLogDB(bool enable) { m_enableLogDB = enable; } + void SetLogDBLater(bool value) { m_enableLogDBLater = value; } + private: + FILE* openLogFile(char const* configFileName,char const* configTimeStampFlag, char const* mode); + FILE* openGmlogPerAccount(uint32 account); + + FILE* raLogfile; + FILE* logfile; + FILE* gmLogfile; + FILE* charLogfile; + FILE* dberLogfile; + FILE* chatLogfile; + FILE* arenaLogFile; + + // cache values for after initilization use (like gm log per account case) + std::string m_logsDir; + std::string m_logsTimestamp; + + // gm log control + bool m_gmlog_per_account; + std::string m_gmlog_filename_format; + + bool m_enableLogDBLater; + bool m_enableLogDB; + uint32 realm; + + // log coloring + bool m_colored; + ColorTypes m_colors[4]; + + // log levels: + // 0 minimum/string, 1 basic/error, 2 detail, 3 full/debug + uint8 m_dbLogLevel; + uint8 m_logLevel; + uint8 m_logFileLevel; + uint8 m_logFilter; + bool m_dbChar; + bool m_dbRA; + bool m_dbGM; + bool m_dbChat; + bool m_charLog_Dump; + bool m_charLog_Dump_Separate; + std::string m_dumpsDir; +}; + +#define sLog Trinity::Singleton<Log>::Instance() + +#ifdef TRINITY_DEBUG +#define DEBUG_LOG Trinity::Singleton<Log>::Instance().outDebug +#else +#define DEBUG_LOG +#endif + +// primary for script library +void outstring_log(const char * str, ...) ATTR_PRINTF(1,2); +void detail_log(const char * str, ...) ATTR_PRINTF(1,2); +void debug_log(const char * str, ...) ATTR_PRINTF(1,2); +void error_log(const char * str, ...) ATTR_PRINTF(1,2); +void error_db_log(const char * str, ...) ATTR_PRINTF(1,2); +#endif + diff --git a/src/server/shared/MemoryLeaks.cpp b/src/server/shared/MemoryLeaks.cpp new file mode 100644 index 00000000000..ef7e36c3b57 --- /dev/null +++ b/src/server/shared/MemoryLeaks.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MemoryLeaks.h" +#include "Policies/SingletonImp.h" + +INSTANTIATE_SINGLETON_1( MemoryManager ) ; + +MemoryManager::MemoryManager( ) +{ + #if COMPILER == MICROSOFT + // standard leak check initialization + //_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + // uncomment to disable Visual Leak Detector from code + //VLDDisable(); + #endif +} diff --git a/src/server/shared/MemoryLeaks.h b/src/server/shared/MemoryLeaks.h new file mode 100644 index 00000000000..c8b8fb8e1b1 --- /dev/null +++ b/src/server/shared/MemoryLeaks.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_MEMORY_H +#define TRINITYSERVER_MEMORY_H + +#include "Platform/CompilerDefs.h" + +#if COMPILER == COMPILER_MICROSOFT + +#ifndef _WIN64 +// Visual Leak Detector support enabled +//#include <vld/vld.h> +// standard Visual Studio leak check disabled, +//# define _CRTDBG_MAP_ALLOC +//# include <stdlib.h> +//# include <crtdbg.h> +#else +//# define _CRTDBG_MAP_ALLOC +//# include <stdlib.h> +//# include <crtdbg.h> +#endif + +#endif + + +#include "Policies/Singleton.h" + +struct MemoryManager : public Trinity::Singleton < MemoryManager > +{ + MemoryManager(); +}; +#endif diff --git a/src/server/shared/PacketLog.cpp b/src/server/shared/PacketLog.cpp new file mode 100644 index 00000000000..4e5cad69605 --- /dev/null +++ b/src/server/shared/PacketLog.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "PacketLog.h" +#include "Config/ConfigEnv.h" +#include "Policies/SingletonImpl.h" + +#include <ctype.h> + +INSTANTIATE_SINGLETON_1( PacketLog ); + +PacketLog::PacketLog() +{ + + if (sConfig.GetBoolDefault("LogRealm", false)) + { + FILE *pFile = fopen("realm.log", "w+"); + fclose(pFile); + } + + if (sConfig.GetBoolDefault("LogWorld", false)) + { + FILE *pFile = fopen("world.log", "w+"); + fclose(pFile); + } +} + +PacketLog::~PacketLog() +{ +} + +char PacketLog::makehexchar(int i) +{ + return (i<=9) ? '0'+i : 'A'+(i-10); +} + +int PacketLog::hextoint(char c) +{ + c = toupper(c); + return (c > '9' ? c - 'A' + 10 : c - '0'); +} + +void PacketLog::HexDump(const unsigned char* data, size_t length, const char* file) +{ + FILE *pFile; + pFile = fopen(file, "a"); + + const int char_offset = 16*3 + 2; + const int line_size = 16*3 + 16 + 3; + char line[line_size+1]; + + fprintf(pFile,"OFFSET 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F | 0123456789ABCDEF\n"); + fprintf(pFile,"--------------------------------------------------------------------------\n"); + + line[char_offset - 1] = ' '; + line[char_offset - 2] = ' '; + + for (size_t i=0; i<length; ) + { + int bi=0; + int ci=0; + + int start_i = i; + + for (int line_i=0; i < length && line_i < 16; i++, line_i++) + { + line[bi++] = makehexchar(*data>>4); + line[bi++] = makehexchar(*data & 0x0f); + line[bi++] = ' '; + line[char_offset+(ci++)]=(isprint(*data) ? *data : '.'); + ++data; + } + + while (bi<16*3) + { + line[bi++]=' '; + } + + line[char_offset+(ci++)]='\n'; + line[char_offset+ci]=0; + + fprintf(pFile,"%06X %s", start_i, line); + } + fprintf(pFile, "\n\n"); + fclose(pFile); +} + +void PacketLog::HexDump(const char *data, size_t length, const char* file) +{ + HexDump((unsigned char *)data, length, file); +} + +void PacketLog::HexDumpStr(const char *msg, const char *data, size_t len, const char* file) +{ + FILE *pFile; + pFile = fopen(file, "a"); + fprintf(pFile,"%s\n", msg); + fclose(pFile); + + HexDump(data, len, file); +} + +void PacketLog::RealmHexDump(RealmPacket* data, uint32 socket, bool direction) +{ + if (!sConfig.GetBoolDefault("LogRealm", false)) + return; + + FILE *pFile; + pFile = fopen("realm.log", "a"); + + uint16 len = data->size() + 2; + uint8 opcode = data->GetOpcode(); + if (direction) + fprintf(pFile, "SERVER:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.2X\nDATA:\n", socket, len, opcode); + else + fprintf(pFile, "CLIENT:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.2X\nDATA:\n", socket, len, opcode); + + fclose(pFile); + HexDump((char *)data->contents(), data->size(), "realm.log"); + +} + +void PacketLog::WorldHexDump(WorldPacket* data, uint32 socket, bool direction) +{ + if (!sConfig.GetBoolDefault("LogWorld", false)) + return; + + FILE *pFile; + pFile = fopen("world.log", "a"); + + uint16 len = data->size(); + uint16 opcode = data->GetOpcode(); + if (direction) + fprintf(pFile, "SERVER:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.4X\nDATA:\n", socket, len, opcode); + else + fprintf(pFile, "CLIENT:\nSOCKET: %d\nLENGTH: %d\nOPCODE: %.4X\nDATA:\n", socket, len, opcode); + + fclose(pFile); + HexDump((char *)data->contents(), data->size(), "world.log"); + +} + diff --git a/src/server/shared/PacketLog.h b/src/server/shared/PacketLog.h new file mode 100644 index 00000000000..462cc1eed51 --- /dev/null +++ b/src/server/shared/PacketLog.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_PACKETLOG_H +#define TRINITYCORE_PACKETLOG_H + +#include "Common.h" +#include "Policies/Singleton.h" +#include "RealmPacket.h" +#include "WorldPacket.h" + +class PacketLog +{ + public: + PacketLog(); + ~PacketLog(); + + int hextoint(char c); + char makehexchar(int i); + + void HexDump(const unsigned char* data, size_t length, const char* file); + void HexDump(const char *data, size_t length, const char* file); + void HexDumpStr(const char *msg, const char *data, size_t len, const char* file); + + void RealmHexDump(RealmPacket * data, uint32 socket, bool direction); + + void WorldHexDump(WorldPacket * data, uint32 socket, bool direction); +}; + +#define sPacketLog Trinity::Singleton<PacketLog>::Instance() +#endif + diff --git a/src/server/shared/ProgressBar.cpp b/src/server/shared/ProgressBar.cpp new file mode 100644 index 00000000000..c24d9f86f6b --- /dev/null +++ b/src/server/shared/ProgressBar.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> + +#include "ProgressBar.h" + +char const* const barGoLink::empty = " "; +#ifdef _WIN32 +char const* const barGoLink::full = "\x3D"; +#else +char const* const barGoLink::full = "*"; +#endif + +barGoLink::~barGoLink() +{ + printf( "\n" ); + fflush(stdout); +} + +barGoLink::barGoLink( int row_count ) +{ + rec_no = 0; + rec_pos = 0; + indic_len = 50; + num_rec = row_count; + #ifdef _WIN32 + printf( "\x3D" ); + #else + printf( "[" ); + #endif + for (int i = 0; i < indic_len; i++ ) printf( empty ); + #ifdef _WIN32 + printf( "\x3D 0%%\r\x3D" ); + #else + printf( "] 0%%\r[" ); + #endif + fflush(stdout); +} + +void barGoLink::step( void ) +{ + int i, n; + + if ( num_rec == 0 ) return; + ++rec_no; + n = rec_no * indic_len / num_rec; + if ( n != rec_pos ) + { + #ifdef _WIN32 + printf( "\r\x3D" ); + #else + printf( "\r[" ); + #endif + for (i = 0; i < n; i++ ) printf( full ); + for (; i < indic_len; i++ ) printf( empty ); + float percent = (((float)n/(float)indic_len)*100); + #ifdef _WIN32 + printf( "\x3D %i%% \r\x3D", (int)percent); + #else + printf( "] %i%% \r[", (int)percent); + #endif + fflush(stdout); + + rec_pos = n; + } +} + diff --git a/src/server/shared/ProgressBar.h b/src/server/shared/ProgressBar.h new file mode 100644 index 00000000000..e7565590278 --- /dev/null +++ b/src/server/shared/ProgressBar.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef TRINITYCORE_PROGRESSBAR_H +#define TRINITYCORE_PROGRESSBAR_H + +#include "Platform/Define.h" + +class barGoLink +{ + static char const * const empty; + static char const * const full; + + int rec_no; + int rec_pos; + int num_rec; + int indic_len; + + public: + + void step( void ); + barGoLink( int ); + ~barGoLink(); +}; +#endif + diff --git a/src/server/shared/ServiceWin32.cpp b/src/server/shared/ServiceWin32.cpp new file mode 100644 index 00000000000..2c1df2ff483 --- /dev/null +++ b/src/server/shared/ServiceWin32.cpp @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef WIN32 + +#include "Common.h" +#include "Log.h" +#include <cstring> +#include <windows.h> +#include <winsvc.h> + +#if !defined(WINADVAPI) +#if !defined(_ADVAPI32_) +#define WINADVAPI DECLSPEC_IMPORT +#else +#define WINADVAPI +#endif +#endif + +extern int main(int argc, char ** argv); +extern char serviceLongName[]; +extern char serviceName[]; +extern char serviceDescription[]; + +extern int m_ServiceStatus; + +SERVICE_STATUS serviceStatus; + +SERVICE_STATUS_HANDLE serviceStatusHandle = 0; + +typedef WINADVAPI BOOL (WINAPI *CSD_T)(SC_HANDLE, DWORD, LPCVOID); + +bool WinServiceInstall() +{ + CSD_T ChangeService_Config2; + HMODULE advapi32; + SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); + + if (serviceControlManager) + { + char path[_MAX_PATH + 10]; + if (GetModuleFileName( 0, path, sizeof(path)/sizeof(path[0]) ) > 0) + { + SC_HANDLE service; + std::strcat(path, " --service"); + service = CreateService(serviceControlManager, + serviceName, // name of service + serviceLongName, // service name to display + SERVICE_ALL_ACCESS, // desired access + // service type + SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, + SERVICE_AUTO_START, // start type + SERVICE_ERROR_IGNORE, // error control type + path, // service's binary + 0, // no load ordering group + 0, // no tag identifier + 0, // no dependencies + 0, // LocalSystem account + 0); // no password + if (service) + { + advapi32 = GetModuleHandle("ADVAPI32.DLL"); + if(!advapi32) + { + CloseServiceHandle(service); + CloseServiceHandle(serviceControlManager); + return false; + } + + ChangeService_Config2 = (CSD_T) GetProcAddress(advapi32, "ChangeServiceConfig2A"); + if (!ChangeService_Config2) + { + CloseServiceHandle(service); + CloseServiceHandle(serviceControlManager); + return false; + } + + SERVICE_DESCRIPTION sdBuf; + sdBuf.lpDescription = serviceDescription; + ChangeService_Config2( + service, // handle to service + SERVICE_CONFIG_DESCRIPTION, // change: description + &sdBuf); // new data + + SC_ACTION _action[1]; + _action[0].Type = SC_ACTION_RESTART; + _action[0].Delay = 10000; + SERVICE_FAILURE_ACTIONS sfa; + ZeroMemory(&sfa, sizeof(SERVICE_FAILURE_ACTIONS)); + sfa.lpsaActions = _action; + sfa.cActions = 1; + sfa.dwResetPeriod =INFINITE; + ChangeService_Config2( + service, // handle to service + SERVICE_CONFIG_FAILURE_ACTIONS, // information level + &sfa); // new data + + CloseServiceHandle(service); + + } + } + CloseServiceHandle(serviceControlManager); + } + return true; +} + +bool WinServiceUninstall() +{ + SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT); + + if (serviceControlManager) + { + SC_HANDLE service = OpenService(serviceControlManager, + serviceName, SERVICE_QUERY_STATUS | DELETE); + if (service) + { + SERVICE_STATUS serviceStatus2; + if (QueryServiceStatus(service, &serviceStatus2)) + { + if (serviceStatus2.dwCurrentState == SERVICE_STOPPED) + DeleteService(service); + } + CloseServiceHandle(service); + } + + CloseServiceHandle(serviceControlManager); + } + return true; +} + +void WINAPI ServiceControlHandler(DWORD controlCode) +{ + switch (controlCode) + { + case SERVICE_CONTROL_INTERROGATE: + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + + m_ServiceStatus = 0; + return; + + case SERVICE_CONTROL_PAUSE: + m_ServiceStatus = 2; + serviceStatus.dwCurrentState = SERVICE_PAUSED; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + break; + + case SERVICE_CONTROL_CONTINUE: + serviceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + m_ServiceStatus = 1; + break; + + default: + if ( controlCode >= 128 && controlCode <= 255 ) + // user defined control code + break; + else + // unrecognized control code + break; + } + + SetServiceStatus(serviceStatusHandle, &serviceStatus); +} + +void WINAPI ServiceMain(DWORD argc, char *argv[]) +{ + // initialise service status + serviceStatus.dwServiceType = SERVICE_WIN32; + serviceStatus.dwCurrentState = SERVICE_START_PENDING; + serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; + serviceStatus.dwWin32ExitCode = NO_ERROR; + serviceStatus.dwServiceSpecificExitCode = NO_ERROR; + serviceStatus.dwCheckPoint = 0; + serviceStatus.dwWaitHint = 0; + + serviceStatusHandle = RegisterServiceCtrlHandler(serviceName, ServiceControlHandler); + + if ( serviceStatusHandle ) + { + char path[_MAX_PATH + 1]; + unsigned int i, last_slash = 0; + + GetModuleFileName(0, path, sizeof(path)/sizeof(path[0])); + + for (i = 0; i < std::strlen(path); i++) + { + if (path[i] == '\\') last_slash = i; + } + + path[last_slash] = 0; + + // service is starting + serviceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + + // do initialisation here + SetCurrentDirectory(path); + + // running + serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + serviceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus( serviceStatusHandle, &serviceStatus ); + + //////////////////////// + // service main cycle // + //////////////////////// + + m_ServiceStatus = 1; + argc = 1; + main(argc , argv); + + // service was stopped + serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + + // do cleanup here + + // service is now stopped + serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + serviceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + } +} + +bool WinServiceRun() +{ + SERVICE_TABLE_ENTRY serviceTable[] = + { + { serviceName, ServiceMain }, + { 0, 0 } + }; + + if (!StartServiceCtrlDispatcher(serviceTable)) + { + sLog.outError("StartService Failed. Error [%u]", ::GetLastError()); + return false; + } + return true; +} +#endif + diff --git a/src/server/shared/ServiceWin32.h b/src/server/shared/ServiceWin32.h new file mode 100644 index 00000000000..ddac785a0fb --- /dev/null +++ b/src/server/shared/ServiceWin32.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef WIN32 +#ifndef _WIN32_SERVICE_ +#define _WIN32_SERVICE_ + +bool WinServiceInstall(); +bool WinServiceUninstall(); +bool WinServiceRun(); + +#endif // _WIN32_SERVICE_ +#endif // WIN32 + diff --git a/src/server/shared/SignalHandler.h b/src/server/shared/SignalHandler.h new file mode 100644 index 00000000000..0c4d8143c41 --- /dev/null +++ b/src/server/shared/SignalHandler.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SIGNAL_HANDLER_H__ +#define __SIGNAL_HANDLER_H__ + +#include <ace/Event_Handler.h> + +namespace Trinity +{ + +/// Handle termination signals +class SignalHandler : public ACE_Event_Handler +{ + public: + int handle_signal(int SigNum, siginfo_t* = NULL, ucontext_t* = NULL) + { + HandleSignal(SigNum); + return 0; + } + virtual void HandleSignal(int SigNum) {}; +}; + +} + +#endif /* __SIGNAL_HANDLER_H__ */ diff --git a/src/server/shared/SystemConfig.h b/src/server/shared/SystemConfig.h new file mode 100644 index 00000000000..ac531cbbc94 --- /dev/null +++ b/src/server/shared/SystemConfig.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// THIS FILE IS DEPRECATED + +#ifndef TRINITY_SYSTEMCONFIG_H +#define TRINITY_SYSTEMCONFIG_H + +#include "Platform/Define.h" +#include "revision.h" + +#define _PACKAGENAME "TrinityCore " +#define _CODENAME "LONG_COLD_WINTER" + +#if TRINITY_ENDIAN == TRINITY_BIGENDIAN +# define _ENDIAN_STRING "big-endian" +#else +# define _ENDIAN_STRING "little-endian" +#endif + +#if PLATFORM == PLATFORM_WINDOWS +# ifdef _WIN64 +# define _FULLVERSION _PACKAGENAME "Rev: " _REVISION " " _BUILD_DIRECTIVE " Hash: " _HASH " (Win64," _ENDIAN_STRING ")" +# else +# define _FULLVERSION _PACKAGENAME "Rev: " _REVISION " " _BUILD_DIRECTIVE " Hash: " _HASH " (Win32," _ENDIAN_STRING ")" +# endif +#else +# define _FULLVERSION _PACKAGENAME "Rev: " _REVISION " " _BUILD_DIRECTIVE " Hash: " _HASH " (Unix," _ENDIAN_STRING ")" +#endif + +#define DEFAULT_PLAYER_LIMIT 100 +#define DEFAULT_WORLDSERVER_PORT 8085 //8129 +#define DEFAULT_REALMSERVER_PORT 3724 +#define DEFAULT_SOCKET_SELECT_TIME 10000 +#endif + diff --git a/src/server/shared/Threading.cpp b/src/server/shared/Threading.cpp new file mode 100644 index 00000000000..3938286dbdb --- /dev/null +++ b/src/server/shared/Threading.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Threading.h" +#include "Errors.h" +#include <ace/OS_NS_unistd.h> +#include <ace/Sched_Params.h> +#include <vector> + +using namespace ACE_Based; + +ThreadPriority::ThreadPriority() +{ + for (int i = Idle; i < MAXPRIORITYNUM; ++i) + m_priority[i] = ACE_THR_PRI_OTHER_DEF; + + m_priority[Idle] = ACE_Sched_Params::priority_min(ACE_SCHED_OTHER); + m_priority[Realtime] = ACE_Sched_Params::priority_max(ACE_SCHED_OTHER); + + std::vector<int> _tmp; + + ACE_Sched_Params::Policy _policy = ACE_SCHED_OTHER; + ACE_Sched_Priority_Iterator pr_iter(_policy); + + while (pr_iter.more()) + { + _tmp.push_back(pr_iter.priority()); + pr_iter.next(); + } + + ASSERT (!_tmp.empty()); + + if(_tmp.size() >= MAXPRIORITYNUM) + { + const size_t max_pos = _tmp.size(); + size_t min_pos = 1; + size_t norm_pos = 0; + for (size_t i = 0; i < max_pos; ++i) + { + if(_tmp[i] == ACE_THR_PRI_OTHER_DEF) + { + norm_pos = i + 1; + break; + } + } + + //since we have only 7(seven) values in enum Priority + //and 3 we know already (Idle, Normal, Realtime) so + //we need to split each list [Idle...Normal] and [Normal...Realtime] + //into ¹ piesces + const size_t _divider = 4; + size_t _div = (norm_pos - min_pos) / _divider; + if(_div == 0) + _div = 1; + + min_pos = (norm_pos - 1); + + m_priority[Low] = _tmp[min_pos -= _div]; + m_priority[Lowest] = _tmp[min_pos -= _div ]; + + _div = (max_pos - norm_pos) / _divider; + if(_div == 0) + _div = 1; + + min_pos = norm_pos - 1; + + m_priority[High] = _tmp[min_pos += _div]; + m_priority[Highest] = _tmp[min_pos += _div]; + } +} + +int ThreadPriority::getPriority(Priority p) const +{ + if(p < Idle) + p = Idle; + + if(p > Realtime) + p = Realtime; + + return m_priority[p]; +} + +#define THREADFLAG (THR_NEW_LWP | THR_SCHED_DEFAULT| THR_JOINABLE) + +Thread::Thread() : m_task(0), m_iThreadId(0), m_hThreadHandle(0) +{ + +} + +Thread::Thread(Runnable* instance) : m_task(instance), m_iThreadId(0), m_hThreadHandle(0) +{ + // register reference to m_task to prevent it deeltion until destructor + if (m_task) + m_task->incReference(); + + bool _start = start(); + ASSERT (_start); +} + +Thread::~Thread() +{ + //Wait(); + + // deleted runnable object (if no other references) + if (m_task) + m_task->decReference(); +} + +//initialize Thread's class static member +Thread::ThreadStorage Thread::m_ThreadStorage; +ThreadPriority Thread::m_TpEnum; + +bool Thread::start() +{ + if (m_task == 0 || m_iThreadId != 0) + return false; + + bool res = (ACE_Thread::spawn(&Thread::ThreadTask, (void*)m_task, THREADFLAG, &m_iThreadId, &m_hThreadHandle) == 0); + + if (res) + m_task->incReference(); + + return res; +} + +bool Thread::wait() +{ + if (!m_hThreadHandle || !m_task) + return false; + + ACE_THR_FUNC_RETURN _value = ACE_THR_FUNC_RETURN(-1); + int _res = ACE_Thread::join(m_hThreadHandle, &_value); + + m_iThreadId = 0; + m_hThreadHandle = 0; + + return (_res == 0); +} + +void Thread::destroy() +{ + if (!m_iThreadId || !m_task) + return; + + if (ACE_Thread::kill(m_iThreadId, -1) != 0) + return; + + m_iThreadId = 0; + m_hThreadHandle = 0; + + // reference set at ACE_Thread::spawn + m_task->decReference(); +} + +void Thread::suspend() +{ + ACE_Thread::suspend(m_hThreadHandle); +} + +void Thread::resume() +{ + ACE_Thread::resume(m_hThreadHandle); +} + +ACE_THR_FUNC_RETURN Thread::ThreadTask(void * param) +{ + Runnable * _task = (Runnable*)param; + _task->run(); + + // task execution complete, free referecne added at + _task->decReference(); + + return (ACE_THR_FUNC_RETURN)0; +} + +ACE_thread_t Thread::currentId() +{ + return ACE_Thread::self(); +} + +ACE_hthread_t Thread::currentHandle() +{ + ACE_hthread_t _handle; + ACE_Thread::self(_handle); + + return _handle; +} + +Thread * Thread::current() +{ + Thread * _thread = m_ThreadStorage.ts_object(); + if(!_thread) + { + _thread = new Thread(); + _thread->m_iThreadId = Thread::currentId(); + _thread->m_hThreadHandle = Thread::currentHandle(); + + Thread * _oldValue = m_ThreadStorage.ts_object(_thread); + if(_oldValue) + delete _oldValue; + } + + return _thread; +} + +void Thread::setPriority(Priority type) +{ + int _priority = m_TpEnum.getPriority(type); + int _ok = ACE_Thread::setprio(m_hThreadHandle, _priority); + //remove this ASSERT in case you don't want to know is thread priority change was successful or not + ASSERT (_ok == 0); +} + +void Thread::Sleep(unsigned long msecs) +{ + ACE_OS::sleep(ACE_Time_Value(0, 1000 * msecs)); +} diff --git a/src/server/shared/Threading.h b/src/server/shared/Threading.h new file mode 100644 index 00000000000..fa046117c6e --- /dev/null +++ b/src/server/shared/Threading.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef THREADING_H +#define THREADING_H + +#include <ace/Thread.h> +#include <ace/TSS_T.h> +#include "ace/Atomic_Op.h" +#include <assert.h> + +namespace ACE_Based +{ + + class Runnable + { + public: + virtual ~Runnable() {} + virtual void run() = 0; + + void incReference() { ++m_refs; } + void decReference() + { + if(!--m_refs) + delete this; + } + private: + ACE_Atomic_Op<ACE_Thread_Mutex, long> m_refs; + }; + + enum Priority + { + Idle, + Lowest, + Low, + Normal, + High, + Highest, + Realtime, + }; + +#define MAXPRIORITYNUM (Realtime + 1) + + class ThreadPriority + { + public: + ThreadPriority(); + int getPriority(Priority p) const; + + private: + int m_priority[MAXPRIORITYNUM]; + }; + + class Thread + { + public: + Thread(); + explicit Thread(Runnable* instance); + ~Thread(); + + bool start(); + bool wait(); + void destroy(); + + void suspend(); + void resume(); + + void setPriority(Priority type); + + static void Sleep(unsigned long msecs); + static ACE_thread_t currentId(); + static ACE_hthread_t currentHandle(); + static Thread * current(); + + private: + Thread(const Thread&); + Thread& operator=(const Thread&); + + static ACE_THR_FUNC_RETURN ThreadTask(void * param); + + ACE_thread_t m_iThreadId; + ACE_hthread_t m_hThreadHandle; + Runnable * m_task; + + typedef ACE_TSS<Thread> ThreadStorage; + //global object - container for Thread class representation of every thread + static ThreadStorage m_ThreadStorage; + //use this object to determine current OS thread priority values mapped to enum Priority{} + static ThreadPriority m_TpEnum; + }; + +} +#endif diff --git a/src/server/shared/Timer.h b/src/server/shared/Timer.h new file mode 100644 index 00000000000..3e0a369b655 --- /dev/null +++ b/src/server/shared/Timer.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITY_TIMER_H +#define TRINITY_TIMER_H + +#include "Platform/CompilerDefs.h" + +#if PLATFORM == PLATFORM_WINDOWS +# include <ace/config-all.h> +# include <mmsystem.h> +# include <time.h> +#else +# if defined(__APPLE_CC__) +# include <time.h> +# endif +# include <sys/time.h> +# include <sys/timeb.h> +#endif + +#if PLATFORM == PLATFORM_WINDOWS +inline uint32 getMSTime() { return GetTickCount(); } +#else +inline uint32 getMSTime() +{ + struct timeval tv; + struct timezone tz; + gettimeofday( &tv, &tz ); + return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} +#endif + +inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime) +{ + // getMSTime() have limited data range and this is case when it overflow in this tick + if (oldMSTime > newMSTime) + return (0xFFFFFFFF - oldMSTime) + newMSTime; + else + return newMSTime - oldMSTime; +} + +struct IntervalTimer +{ + public: + + IntervalTimer() + : _interval(0), _current(0) + { + } + + void Update(time_t diff) + { + _current += diff; + if (_current < 0) + _current = 0; + } + + bool Passed() + { + return _current >= _interval; + } + + void Reset() + { + if (_current >= _interval) + _current -= _interval; + } + + void SetCurrent(time_t current) + { + _current = current; + } + + void SetInterval(time_t interval) + { + _interval = interval; + } + + time_t GetInterval() const + { + return _interval; + } + + time_t GetCurrent() const + { + return _current; + } + + private: + + time_t _interval; + time_t _current; +}; + +struct TimeTracker +{ + public: + + TimeTracker(time_t expiry) + : i_expiryTime(expiry) + { + } + + void Update(time_t diff) + { + i_expiryTime -= diff; + } + + bool Passed() const + { + return i_expiryTime <= 0; + } + + void Reset(time_t interval) + { + i_expiryTime = interval; + } + + time_t GetExpiry() const + { + return i_expiryTime; + } + + private: + + time_t i_expiryTime; +}; + +struct TimeTrackerSmall +{ + public: + + TimeTrackerSmall(uint32 expiry) + : i_expiryTime(expiry) + { + } + + void Update(int32 diff) + { + i_expiryTime -= diff; + } + + bool Passed() const + { + return i_expiryTime <= 0; + } + + void Reset(uint32 interval) + { + i_expiryTime = interval; + } + + int32 GetExpiry() const + { + return i_expiryTime; + } + + private: + + int32 i_expiryTime; +}; + +struct PeriodicTimer +{ + public: + + PeriodicTimer(int32 period, int32 start_time) + : i_expireTime(start_time), i_period(period) + { + } + + bool Update(const uint32 &diff) + { + if ((i_expireTime -= diff) > 0) + return false; + + i_expireTime += i_period > diff ? i_period : diff; + return true; + } + + void SetPeriodic(int32 period, int32 start_time) + { + i_expireTime = start_time; + i_period = period; + } + + // Tracker interface + void TUpdate(int32 diff) { i_expireTime -= diff; } + bool TPassed() const { return i_expireTime <= 0; } + void TReset(int32 diff, int32 period) { i_expireTime += period > diff ? period : diff; } + + private: + + int32 i_period; + int32 i_expireTime; +}; + +#endif diff --git a/src/server/shared/Util.cpp b/src/server/shared/Util.cpp new file mode 100644 index 00000000000..a3c017fdbfd --- /dev/null +++ b/src/server/shared/Util.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Util.h" + +#include "sockets/socket_include.h" +#include "utf8cpp/utf8.h" +#include "mersennetwister/MersenneTwister.h" +#include <ace/TSS_T.h> + +typedef ACE_TSS<MTRand> MTRandTSS; +static MTRandTSS mtRand; + +int32 irand (int32 min, int32 max) +{ + return int32 (mtRand->randInt (max - min)) + min; +} + +uint32 urand (uint32 min, uint32 max) +{ + return mtRand->randInt (max - min) + min; +} + +int32 rand32 () +{ + return mtRand->randInt (); +} + +double rand_norm(void) +{ + return mtRand->randExc (); +} + +double rand_chance (void) +{ + return mtRand->randExc (100.0); +} + +Tokens StrSplit(const std::string &src, const std::string &sep) +{ + Tokens r; + std::string s; + for (std::string::const_iterator i = src.begin(); i != src.end(); i++) + { + if (sep.find(*i) != std::string::npos) + { + if (s.length()) r.push_back(s); + s = ""; + } + else + { + s += *i; + } + } + if (s.length()) r.push_back(s); + return r; +} + +void stripLineInvisibleChars(std::string &str) +{ + static std::string invChars = " \t\7\n"; + + size_t wpos = 0; + + bool space = false; + for (size_t pos = 0; pos < str.size(); ++pos) + { + if(invChars.find(str[pos])!=std::string::npos) + { + if(!space) + { + str[wpos++] = ' '; + space = true; + } + } + else + { + if(wpos!=pos) + str[wpos++] = str[pos]; + else + ++wpos; + space = false; + } + } + + if(wpos < str.size()) + str.erase(wpos,str.size()); + if(str.find("|TInterface")!=std::string::npos) + str.clear(); + +} + +std::string secsToTimeString(uint32 timeInSecs, bool shortText, bool hoursOnly) +{ + uint32 secs = timeInSecs % MINUTE; + uint32 minutes = timeInSecs % HOUR / MINUTE; + uint32 hours = timeInSecs % DAY / HOUR; + uint32 days = timeInSecs / DAY; + + std::ostringstream ss; + if(days) + ss << days << (shortText ? "d" : " Day(s) "); + if(hours || hoursOnly) + ss << hours << (shortText ? "h" : " Hour(s) "); + if(!hoursOnly) + { + if(minutes) + ss << minutes << (shortText ? "m" : " Minute(s) "); + if(secs || (!days && !hours && !minutes) ) + ss << secs << (shortText ? "s" : " Second(s)."); + } + + return ss.str(); +} + +uint32 TimeStringToSecs(const std::string& timestring) +{ + uint32 secs = 0; + uint32 buffer = 0; + uint32 multiplier = 0; + + for (std::string::const_iterator itr = timestring.begin(); itr != timestring.end(); itr++ ) + { + if(isdigit(*itr)) + { + buffer*=10; + buffer+= (*itr)-'0'; + } + else + { + switch(*itr) + { + case 'd': multiplier = DAY; break; + case 'h': multiplier = HOUR; break; + case 'm': multiplier = MINUTE; break; + case 's': multiplier = 1; break; + default : return 0; //bad format + } + buffer*=multiplier; + secs+=buffer; + buffer=0; + } + } + + return secs; +} + +std::string TimeToTimestampStr(time_t t) +{ + tm* aTm = localtime(&t); + // YYYY year + // MM month (2 digits 01-12) + // DD day (2 digits 01-31) + // HH hour (2 digits 00-23) + // MM minutes (2 digits 00-59) + // SS seconds (2 digits 00-59) + char buf[20]; + snprintf(buf,20,"%04d-%02d-%02d_%02d-%02d-%02d",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec); + return std::string(buf); +} + +/// Check if the string is a valid ip address representation +bool IsIPAddress(char const* ipaddress) +{ + if(!ipaddress) + return false; + + // Let the big boys do it. + // Drawback: all valid ip address formats are recognized e.g.: 12.23,121234,0xABCD) + return inet_addr(ipaddress) != INADDR_NONE; +} + +/// create PID file +uint32 CreatePIDFile(const std::string& filename) +{ + FILE * pid_file = fopen (filename.c_str(), "w" ); + if (pid_file == NULL) + return 0; + +#ifdef WIN32 + DWORD pid = GetCurrentProcessId(); +#else + pid_t pid = getpid(); +#endif + + fprintf(pid_file, "%d", pid ); + fclose(pid_file); + + return (uint32)pid; +} + +size_t utf8length(std::string& utf8str) +{ + try + { + return utf8::distance(utf8str.c_str(),utf8str.c_str()+utf8str.size()); + } + catch(std::exception) + { + utf8str = ""; + return 0; + } +} + +void utf8truncate(std::string& utf8str,size_t len) +{ + try + { + size_t wlen = utf8::distance(utf8str.c_str(),utf8str.c_str()+utf8str.size()); + if(wlen <= len) + return; + + std::wstring wstr; + wstr.resize(wlen); + utf8::utf8to16(utf8str.c_str(),utf8str.c_str()+utf8str.size(),&wstr[0]); + wstr.resize(len); + char* oend = utf8::utf16to8(wstr.c_str(),wstr.c_str()+wstr.size(),&utf8str[0]); + utf8str.resize(oend-(&utf8str[0])); // remove unused tail + } + catch(std::exception) + { + utf8str = ""; + } +} + +bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize) +{ + try + { + size_t len = utf8::distance(utf8str,utf8str+csize); + if(len > wsize) + { + if(wsize > 0) + wstr[0] = L'\0'; + wsize = 0; + return false; + } + + wsize = len; + utf8::utf8to16(utf8str,utf8str+csize,wstr); + wstr[len] = L'\0'; + } + catch(std::exception) + { + if(wsize > 0) + wstr[0] = L'\0'; + wsize = 0; + return false; + } + + return true; +} + +bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr) +{ + try + { + size_t len = utf8::distance(utf8str.c_str(),utf8str.c_str()+utf8str.size()); + wstr.resize(len); + + utf8::utf8to16(utf8str.c_str(),utf8str.c_str()+utf8str.size(),&wstr[0]); + } + catch(std::exception) + { + wstr = L""; + return false; + } + + return true; +} + +bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str) +{ + try + { + std::string utf8str2; + utf8str2.resize(size*4); // allocate for most long case + + char* oend = utf8::utf16to8(wstr,wstr+size,&utf8str2[0]); + utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail + utf8str = utf8str2; + } + catch(std::exception) + { + utf8str = ""; + return false; + } + + return true; +} + +bool WStrToUtf8(std::wstring wstr, std::string& utf8str) +{ + try + { + std::string utf8str2; + utf8str2.resize(wstr.size()*4); // allocate for most long case + + char* oend = utf8::utf16to8(wstr.c_str(),wstr.c_str()+wstr.size(),&utf8str2[0]); + utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail + utf8str = utf8str2; + } + catch(std::exception) + { + utf8str = ""; + return false; + } + + return true; +} + +typedef wchar_t const* const* wstrlist; + +std::wstring GetMainPartOfName(std::wstring wname, uint32 declension) +{ + // supported only Cyrillic cases + if(wname.size() < 1 || !isCyrillicCharacter(wname[0]) || declension > 5) + return wname; + + // Important: end length must be <= MAX_INTERNAL_PLAYER_NAME-MAX_PLAYER_NAME (3 currently) + + static wchar_t const a_End[] = { wchar_t(1), wchar_t(0x0430),wchar_t(0x0000)}; + static wchar_t const o_End[] = { wchar_t(1), wchar_t(0x043E),wchar_t(0x0000)}; + static wchar_t const ya_End[] = { wchar_t(1), wchar_t(0x044F),wchar_t(0x0000)}; + static wchar_t const ie_End[] = { wchar_t(1), wchar_t(0x0435),wchar_t(0x0000)}; + static wchar_t const i_End[] = { wchar_t(1), wchar_t(0x0438),wchar_t(0x0000)}; + static wchar_t const yeru_End[] = { wchar_t(1), wchar_t(0x044B),wchar_t(0x0000)}; + static wchar_t const u_End[] = { wchar_t(1), wchar_t(0x0443),wchar_t(0x0000)}; + static wchar_t const yu_End[] = { wchar_t(1), wchar_t(0x044E),wchar_t(0x0000)}; + static wchar_t const oj_End[] = { wchar_t(2), wchar_t(0x043E),wchar_t(0x0439),wchar_t(0x0000)}; + static wchar_t const ie_j_End[] = { wchar_t(2), wchar_t(0x0435),wchar_t(0x0439),wchar_t(0x0000)}; + static wchar_t const io_j_End[] = { wchar_t(2), wchar_t(0x0451),wchar_t(0x0439),wchar_t(0x0000)}; + static wchar_t const o_m_End[] = { wchar_t(2), wchar_t(0x043E),wchar_t(0x043C),wchar_t(0x0000)}; + static wchar_t const io_m_End[] = { wchar_t(2), wchar_t(0x0451),wchar_t(0x043C),wchar_t(0x0000)}; + static wchar_t const ie_m_End[] = { wchar_t(2), wchar_t(0x0435),wchar_t(0x043C),wchar_t(0x0000)}; + static wchar_t const soft_End[] = { wchar_t(1), wchar_t(0x044C),wchar_t(0x0000)}; + static wchar_t const j_End[] = { wchar_t(1), wchar_t(0x0439),wchar_t(0x0000)}; + + static wchar_t const* const dropEnds[6][8] = { + { &a_End[1], &o_End[1], &ya_End[1], &ie_End[1], &soft_End[1], &j_End[1], NULL, NULL }, + { &a_End[1], &ya_End[1], &yeru_End[1], &i_End[1], NULL, NULL, NULL, NULL }, + { &ie_End[1], &u_End[1], &yu_End[1], &i_End[1], NULL, NULL, NULL, NULL }, + { &u_End[1], &yu_End[1], &o_End[1], &ie_End[1], &soft_End[1], &ya_End[1], &a_End[1], NULL }, + { &oj_End[1], &io_j_End[1], &ie_j_End[1], &o_m_End[1], &io_m_End[1], &ie_m_End[1], &yu_End[1], NULL }, + { &ie_End[1], &i_End[1], NULL, NULL, NULL, NULL, NULL, NULL } + }; + + for (wchar_t const * const* itr = &dropEnds[declension][0]; *itr; ++itr) + { + size_t len = size_t((*itr)[-1]); // get length from string size field + + if(wname.substr(wname.size()-len,len)==*itr) + return wname.substr(0,wname.size()-len); + } + + return wname; +} + +bool utf8ToConsole(const std::string& utf8str, std::string& conStr) +{ +#if PLATFORM == PLATFORM_WINDOWS + std::wstring wstr; + if(!Utf8toWStr(utf8str,wstr)) + return false; + + conStr.resize(wstr.size()); + CharToOemBuffW(&wstr[0],&conStr[0],wstr.size()); +#else + // not implemented yet + conStr = utf8str; +#endif + + return true; +} + +bool consoleToUtf8(const std::string& conStr,std::string& utf8str) +{ +#if PLATFORM == PLATFORM_WINDOWS + std::wstring wstr; + wstr.resize(conStr.size()); + OemToCharBuffW(&conStr[0],&wstr[0],conStr.size()); + + return WStrToUtf8(wstr,utf8str); +#else + // not implemented yet + utf8str = conStr; + return true; +#endif +} + +bool Utf8FitTo(const std::string& str, std::wstring search) +{ + std::wstring temp; + + if(!Utf8toWStr(str,temp)) + return false; + + // converting to lower case + wstrToLower( temp ); + + if(temp.find(search) == std::wstring::npos) + return false; + + return true; +} + +void utf8printf(FILE *out, const char *str, ...) +{ + va_list ap; + va_start(ap, str); + vutf8printf(out, str, &ap); + va_end(ap); +} + +void vutf8printf(FILE *out, const char *str, va_list* ap) +{ +#if PLATFORM == PLATFORM_WINDOWS + char temp_buf[32*1024]; + wchar_t wtemp_buf[32*1024]; + + size_t temp_len = vsnprintf(temp_buf, 32*1024, str, *ap); + + size_t wtemp_len = 32*1024-1; + Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len); + + CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len+1); + fprintf(out, temp_buf); +#else + vfprintf(out, str, *ap); +#endif +} + +void hexEncodeByteArray(uint8* bytes, uint32 arrayLen, std::string& result) +{ + std::ostringstream ss; + for (uint32 i=0; i<arrayLen; ++i) + { + for (uint8 j=0; j<2; ++j) + { + unsigned char nibble = 0x0F & (bytes[i]>>((1-j)*4)); + char encodedNibble; + if(nibble < 0x0A) + encodedNibble = '0'+nibble; + else + encodedNibble = 'A'+nibble-0x0A; + ss << encodedNibble; + } + } + result = ss.str(); +} + diff --git a/src/server/shared/Util.h b/src/server/shared/Util.h new file mode 100644 index 00000000000..4f997725d25 --- /dev/null +++ b/src/server/shared/Util.h @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include "Common.h" + +#include <string> +#include <vector> + +typedef std::vector<std::string> Tokens; + +Tokens StrSplit(const std::string &src, const std::string &sep); + +void stripLineInvisibleChars(std::string &src); + +std::string secsToTimeString(uint32 timeInSecs, bool shortText = false, bool hoursOnly = false); +uint32 TimeStringToSecs(const std::string& timestring); +std::string TimeToTimestampStr(time_t t); + +inline uint32 secsToTimeBitFields(time_t secs) +{ + tm* lt = localtime(&secs); + return (lt->tm_year - 100) << 24 | lt->tm_mon << 20 | (lt->tm_mday - 1) << 14 | lt->tm_wday << 11 | lt->tm_hour << 6 | lt->tm_min; +} + +/* Return a random number in the range min..max; (max-min) must be smaller than 32768. */ + int32 irand(int32 min, int32 max); + +/* Return a random number in the range min..max (inclusive). For reliable results, the difference +* between max and min should be less than RAND32_MAX. */ + uint32 urand(uint32 min, uint32 max); + +/* Return a random number in the range 0 .. RAND32_MAX. */ + int32 rand32(); + +/* Return a random double from 0.0 to 1.0 (exclusive). Floats support only 7 valid decimal digits. + * A double supports up to 15 valid decimal digits and is used internally (RAND32_MAX has 10 digits). + * With an FPU, there is usually no difference in performance between float and double. */ + double rand_norm(void); + +/* Return a random double from 0.0 to 99.9999999999999. Floats support only 7 valid decimal digits. + * A double supports up to 15 valid decimal digits and is used internaly (RAND32_MAX has 10 digits). + * With an FPU, there is usually no difference in performance between float and double. */ + double rand_chance(void); + +/* Return true if a random roll fits in the specified chance (range 0-100). */ +inline bool roll_chance_f(float chance) +{ + return chance > rand_chance(); +} + +/* Return true if a random roll fits in the specified chance (range 0-100). */ +inline bool roll_chance_i(int chance) +{ + return chance > irand(0, 99); +} + +inline void ApplyModUInt32Var(uint32& var, int32 val, bool apply) +{ + int32 cur = var; + cur += (apply ? val : -val); + if(cur < 0) + cur = 0; + var = cur; +} + +inline void ApplyModFloatVar(float& var, float val, bool apply) +{ + var += (apply ? val : -val); + if(var < 0) + var = 0; +} + +inline void ApplyPercentModFloatVar(float& var, float val, bool apply) +{ + if (val == -100.0f) // prevent set var to zero + val = -99.99f; + var *= (apply?(100.0f+val)/100.0f : 100.0f / (100.0f+val)); +} + +bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr); +// in wsize==max size of buffer, out wsize==real string size +bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize); +inline bool Utf8toWStr(const std::string& utf8str, wchar_t* wstr, size_t& wsize) +{ + return Utf8toWStr(utf8str.c_str(), utf8str.size(), wstr, wsize); +} + +bool WStrToUtf8(std::wstring wstr, std::string& utf8str); +// size==real string size +bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str); + +size_t utf8length(std::string& utf8str); // set string to "" if invalid utf8 sequence +void utf8truncate(std::string& utf8str,size_t len); + +inline bool isBasicLatinCharacter(wchar_t wchar) +{ + if(wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z + return true; + if(wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z + return true; + return false; +} + +inline bool isExtendedLatinCharacter(wchar_t wchar) +{ + if(isBasicLatinCharacter(wchar)) + return true; + if(wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS + return true; + if(wchar >= 0x00D8 && wchar <= 0x00DF) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN + return true; + if(wchar == 0x00DF) // LATIN SMALL LETTER SHARP S + return true; + if(wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS + return true; + if(wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN + return true; + if(wchar >= 0x0100 && wchar <= 0x012F) // LATIN CAPITAL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK + return true; + if(wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S + return true; + return false; +} + +inline bool isCyrillicCharacter(wchar_t wchar) +{ + if(wchar >= 0x0410 && wchar <= 0x044F) // CYRILLIC CAPITAL LETTER A - CYRILLIC SMALL LETTER YA + return true; + if(wchar == 0x0401 || wchar == 0x0451) // CYRILLIC CAPITAL LETTER IO, CYRILLIC SMALL LETTER IO + return true; + return false; +} + +inline bool isEastAsianCharacter(wchar_t wchar) +{ + if(wchar >= 0x1100 && wchar <= 0x11F9) // Hangul Jamo + return true; + if(wchar >= 0x3041 && wchar <= 0x30FF) // Hiragana + Katakana + return true; + if(wchar >= 0x3131 && wchar <= 0x318E) // Hangul Compatibility Jamo + return true; + if(wchar >= 0x31F0 && wchar <= 0x31FF) // Katakana Phonetic Ext. + return true; + if(wchar >= 0x3400 && wchar <= 0x4DB5) // CJK Ideographs Ext. A + return true; + if(wchar >= 0x4E00 && wchar <= 0x9FC3) // Unified CJK Ideographs + return true; + if(wchar >= 0xAC00 && wchar <= 0xD7A3) // Hangul Syllables + return true; + if(wchar >= 0xFF01 && wchar <= 0xFFEE) // Halfwidth forms + return true; + return false; +} + +inline bool isNumeric(wchar_t wchar) +{ + return (wchar >= L'0' && wchar <=L'9'); +} + +inline bool isNumeric(char c) +{ + return (c >= '0' && c <='9'); +} + +inline bool isNumericOrSpace(wchar_t wchar) +{ + return isNumeric(wchar) || wchar == L' '; +} + +inline bool isBasicLatinString(std::wstring wstr, bool numericOrSpace) +{ + for (size_t i = 0; i < wstr.size(); ++i) + if(!isBasicLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i]))) + return false; + return true; +} + +inline bool isExtendedLatinString(std::wstring wstr, bool numericOrSpace) +{ + for (size_t i = 0; i < wstr.size(); ++i) + if(!isExtendedLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i]))) + return false; + return true; +} + +inline bool isCyrillicString(std::wstring wstr, bool numericOrSpace) +{ + for (size_t i = 0; i < wstr.size(); ++i) + if(!isCyrillicCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i]))) + return false; + return true; +} + +inline bool isEastAsianString(std::wstring wstr, bool numericOrSpace) +{ + for (size_t i = 0; i < wstr.size(); ++i) + if(!isEastAsianCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i]))) + return false; + return true; +} + +inline wchar_t wcharToUpper(wchar_t wchar) +{ + if(wchar >= L'a' && wchar <= L'z') // LATIN SMALL LETTER A - LATIN SMALL LETTER Z + return wchar_t(uint16(wchar)-0x0020); + if(wchar == 0x00DF) // LATIN SMALL LETTER SHARP S + return wchar_t(0x1E9E); + if(wchar >= 0x00E0 && wchar <= 0x00F6) // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS + return wchar_t(uint16(wchar)-0x0020); + if(wchar >= 0x00F8 && wchar <= 0x00FE) // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN + return wchar_t(uint16(wchar)-0x0020); + if(wchar >= 0x0101 && wchar <= 0x012F) // LATIN SMALL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK (only %2=1) + { + if(wchar % 2 == 1) + return wchar_t(uint16(wchar)-0x0001); + } + if(wchar >= 0x0430 && wchar <= 0x044F) // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA + return wchar_t(uint16(wchar)-0x0020); + if(wchar == 0x0451) // CYRILLIC SMALL LETTER IO + return wchar_t(0x0401); + + return wchar; +} + +inline wchar_t wcharToUpperOnlyLatin(wchar_t wchar) +{ + return isBasicLatinCharacter(wchar) ? wcharToUpper(wchar) : wchar; +} + +inline wchar_t wcharToLower(wchar_t wchar) +{ + if(wchar >= L'A' && wchar <= L'Z') // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z + return wchar_t(uint16(wchar)+0x0020); + if(wchar >= 0x00C0 && wchar <= 0x00D6) // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS + return wchar_t(uint16(wchar)+0x0020); + if(wchar >= 0x00D8 && wchar <= 0x00DE) // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN + return wchar_t(uint16(wchar)+0x0020); + if(wchar >= 0x0100 && wchar <= 0x012E) // LATIN CAPITAL LETTER A WITH MACRON - LATIN CAPITAL LETTER I WITH OGONEK (only %2=0) + { + if(wchar % 2 == 0) + return wchar_t(uint16(wchar)+0x0001); + } + if(wchar == 0x1E9E) // LATIN CAPITAL LETTER SHARP S + return wchar_t(0x00DF); + if(wchar == 0x0401) // CYRILLIC CAPITAL LETTER IO + return wchar_t(0x0451); + if(wchar >= 0x0410 && wchar <= 0x042F) // CYRILLIC CAPITAL LETTER A - CYRILLIC CAPITAL LETTER YA + return wchar_t(uint16(wchar)+0x0020); + + return wchar; +} + +inline void wstrToUpper(std::wstring& str) +{ + std::transform( str.begin(), str.end(), str.begin(), wcharToUpper ); +} + +inline void wstrToLower(std::wstring& str) +{ + std::transform( str.begin(), str.end(), str.begin(), wcharToLower ); +} + +std::wstring GetMainPartOfName(std::wstring wname, uint32 declension); + +bool utf8ToConsole(const std::string& utf8str, std::string& conStr); +bool consoleToUtf8(const std::string& conStr,std::string& utf8str); +bool Utf8FitTo(const std::string& str, std::wstring search); +void utf8printf(FILE *out, const char *str, ...); +void vutf8printf(FILE *out, const char *str, va_list* ap); + +bool IsIPAddress(char const* ipaddress); +uint32 CreatePIDFile(const std::string& filename); + +void hexEncodeByteArray(uint8* bytes, uint32 arrayLen, std::string& result); +#endif + +//handler for operations on large flags +#ifndef _FLAG96 +#define _FLAG96 + +#ifndef PAIR64_HIPART +#define PAIR64_HIPART(x) (uint32)((uint64(x) >> 32) & UI64LIT(0x00000000FFFFFFFF)) +#define PAIR64_LOPART(x) (uint32)(uint64(x) & UI64LIT(0x00000000FFFFFFFF)) +#endif + +class flag96 +{ +private: + uint32 part[3]; +public: + flag96(uint32 p1=0,uint32 p2=0,uint32 p3=0) + { + part[0]=p1; + part[1]=p2; + part[2]=p3; + } + + flag96(uint64 p1, uint32 p2) + { + part[0]=PAIR64_LOPART(p1); + part[1]=PAIR64_HIPART(p1); + part[2]=p2; + } + + inline bool IsEqual(uint32 p1=0, uint32 p2=0, uint32 p3=0) const + { + return ( + part[0]==p1 && + part[1]==p2 && + part[2]==p3); + }; + + inline bool HasFlag(uint32 p1=0, uint32 p2=0, uint32 p3=0) const + { + return ( + part[0]&p1 || + part[1]&p2 || + part[2]&p3); + }; + + inline void Set(uint32 p1=0, uint32 p2=0, uint32 p3=0) + { + part[0]=p1; + part[1]=p2; + part[2]=p3; + }; + + template<class type> + inline bool operator < (type & right) + { + for (uint8 i=3; i > 0; --i) + { + if (part[i-1]<right.part[i-1]) + return 1; + else if (part[i-1]>right.part[i-1]) + return 0; + } + return 0; + }; + + template<class type> + inline bool operator < (type & right) const + { + for (uint8 i = 3; i > 0; --i) + { + if (part[i-1]<right.part[i-1]) + return 1; + else if (part[i-1]>right.part[i-1]) + return 0; + } + return 0; + }; + + template<class type> + inline bool operator != (type & right) + { + if (part[0]!=right.part[0] + || part[1]!=right.part[1] + || part[2]!=right.part[2]) + return true; + return false; + } + + template<class type> + inline bool operator != (type & right) const + { + if (part[0]!=right.part[0] + || part[1]!=right.part[1] + || part[2]!=right.part[2]) + return true; + return false; + }; + + template<class type> + inline bool operator == (type & right) + { + if (part[0]!=right.part[0] + || part[1]!=right.part[1] + || part[2]!=right.part[2]) + return false; + return true; + }; + + template<class type> + inline bool operator == (type & right) const + { + if (part[0]!=right.part[0] + || part[1]!=right.part[1] + || part[2]!=right.part[2]) + return false; + return true; + }; + + template<class type> + inline void operator = (type & right) + { + part[0]=right.part[0]; + part[1]=right.part[1]; + part[2]=right.part[2]; + }; + + template<class type> + inline flag96 operator & (type & right) + { + flag96 ret(part[0] & right.part[0],part[1] & right.part[1],part[2] & right.part[2]); + return + ret; + }; + template<class type> + inline flag96 operator & (type & right) const + { + flag96 ret(part[0] & right.part[0],part[1] & right.part[1],part[2] & right.part[2]); + return + ret; + }; + + template<class type> + inline void operator &= (type & right) + { + *this=*this & right; + }; + + template<class type> + inline flag96 operator | (type & right) + { + flag96 ret(part[0] | right.part[0],part[1] | right.part[1],part[2] | right.part[2]); + return + ret; + }; + + template<class type> + inline flag96 operator | (type & right) const + { + flag96 ret(part[0] | right.part[0],part[1] | right.part[1],part[2] | right.part[2]); + return + ret; + }; + + template<class type> + inline void operator |= (type & right) + { + *this=*this | right; + }; + + inline void operator ~ () + { + part[2]=~part[2]; + part[1]=~part[1]; + part[0]=~part[0]; + }; + + template<class type> + inline flag96 operator ^ (type & right) + { + flag96 ret(part[0] ^ right.part[0],part[1] ^ right.part[1],part[2] ^ right.part[2]); + return + ret; + }; + + template<class type> + inline flag96 operator ^ (type & right) const + { + flag96 ret(part[0] ^ right.part[0],part[1] ^ right.part[1],part[2] ^ right.part[2]); + return + ret; + }; + + template<class type> + inline void operator ^= (type & right) + { + *this=*this^right; + }; + + inline operator bool() const + { + return( + part[0] != 0 || + part[1] != 0 || + part[2] != 0); + }; + + inline operator bool() + { + return( + part[0] != 0 || + part[1] != 0 || + part[2] != 0); + }; + + inline bool operator ! () const + { + return( + part[0] == 0 && + part[1] == 0 && + part[2] == 0); + }; + + inline bool operator ! () + { + return( + part[0] == 0 && + part[1] == 0 && + part[2] == 0); + }; + + inline uint32 & operator[](uint8 el) + { + return (part[el]); + }; + + inline const uint32 & operator[](uint8 el) const + { + return (part[el]); + }; +}; +#endif diff --git a/src/server/shared/WheatyExceptionReport.cpp b/src/server/shared/WheatyExceptionReport.cpp new file mode 100644 index 00000000000..8fb5d5e2d2a --- /dev/null +++ b/src/server/shared/WheatyExceptionReport.cpp @@ -0,0 +1,1013 @@ +//========================================== +// Matt Pietrek +// MSDN Magazine, 2002 +// FILE: WheatyExceptionReport.CPP +//========================================== +#define WIN32_LEAN_AND_MEAN +#pragma warning(disable:4996) +#pragma warning(disable:4312) +#pragma warning(disable:4311) +#include <windows.h> +#include <tlhelp32.h> +#include <stdio.h> +#include <tchar.h> +#define _NO_CVCONST_H +#include <dbghelp.h> +#include "WheatyExceptionReport.h" +#include "SystemConfig.h" +#include "revision.h" +#define CrashFolder _T("Crashes") +//#pragma comment(linker, "/defaultlib:dbghelp.lib") + +inline LPTSTR ErrorMessage(DWORD dw) +{ + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + return (LPTSTR)lpMsgBuf; +} + +//============================== Global Variables ============================= + +// +// Declare the static variables of the WheatyExceptionReport class +// +TCHAR WheatyExceptionReport::m_szLogFileName[MAX_PATH]; +LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter; +HANDLE WheatyExceptionReport::m_hReportFile; +HANDLE WheatyExceptionReport::m_hProcess; + +// Declare global instance of class +WheatyExceptionReport g_WheatyExceptionReport; + +//============================== Class Methods ============================= + +WheatyExceptionReport::WheatyExceptionReport() // Constructor +{ + // Install the unhandled exception filter function + m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter); + m_hProcess = GetCurrentProcess(); +} + +//============ +// Destructor +//============ +WheatyExceptionReport::~WheatyExceptionReport() +{ + if (m_previousFilter) + SetUnhandledExceptionFilter(m_previousFilter); +} + +//=========================================================== +// Entry point where control comes on an unhandled exception +//=========================================================== +LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter( +PEXCEPTION_POINTERS pExceptionInfo) +{ + TCHAR module_folder_name[MAX_PATH]; + GetModuleFileName(0, module_folder_name, MAX_PATH); + TCHAR* pos = _tcsrchr(module_folder_name, '\\'); + if (!pos) + return 0; + pos[0] = '\0'; + ++pos; + + TCHAR crash_folder_path[MAX_PATH]; + sprintf(crash_folder_path, "%s\\%s", module_folder_name, CrashFolder); + if (!CreateDirectory(crash_folder_path, NULL)) + { + if (GetLastError() != ERROR_ALREADY_EXISTS) + return 0; + } + + SYSTEMTIME systime; + GetLocalTime(&systime); + sprintf(m_szLogFileName, "%s\\%s_[%u-%u_%u-%u-%u].txt", + crash_folder_path, pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond); + + m_hReportFile = CreateFile(m_szLogFileName, + GENERIC_WRITE, + 0, + 0, + OPEN_ALWAYS, + FILE_FLAG_WRITE_THROUGH, + 0); + + if (m_hReportFile) + { + SetFilePointer(m_hReportFile, 0, 0, FILE_END); + + GenerateExceptionReport(pExceptionInfo); + + CloseHandle(m_hReportFile); + m_hReportFile = 0; + } + + if (m_previousFilter) + return m_previousFilter(pExceptionInfo); + else + return EXCEPTION_EXECUTE_HANDLER/*EXCEPTION_CONTINUE_SEARCH*/; +} + +BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxcount) +{ + if (!sProcessorName) + return FALSE; + + HKEY hKey; + LONG lRet; + lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), + 0, KEY_QUERY_VALUE, &hKey); + if (lRet != ERROR_SUCCESS) + return FALSE; + TCHAR szTmp[2048]; + DWORD cntBytes = sizeof(szTmp); + lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), NULL, NULL, + (LPBYTE)szTmp, &cntBytes); + if (lRet != ERROR_SUCCESS) + return FALSE; + ::RegCloseKey(hKey); + sProcessorName[0] = '\0'; + // Skip spaces + TCHAR* psz = szTmp; + while (iswspace(*psz)) + ++psz; + _tcsncpy(sProcessorName, psz, maxcount); + return TRUE; +} + +BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) +{ + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + // If that fails, try using the OSVERSIONINFO structure. + OSVERSIONINFOEX osvi = { 0 }; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + BOOL bOsVersionInfoEx; + bOsVersionInfoEx = ::GetVersionEx((LPOSVERSIONINFO)(&osvi)); + if (!bOsVersionInfoEx) + { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (!::GetVersionEx((OSVERSIONINFO*)&osvi)) + return FALSE; + } + *szVersion = _T('\0'); + TCHAR wszTmp[128]; + switch (osvi.dwPlatformId) + { + // Windows NT product family. + case VER_PLATFORM_WIN32_NT: + // Test for the specific product family. + if (osvi.dwMajorVersion == 6) + _tcsncat(szVersion, _T("Windows Vista or Windows Server 2008 "), cntMax); + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + _tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax); + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) + _tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax); + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + _tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax); + if (osvi.dwMajorVersion <= 4) + _tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax); + + // Test for specific product on Windows NT 4.0 SP6 and later. + if (bOsVersionInfoEx) + { + // Test for the workstation type. + #if WINVER < 0x0500 + if (osvi.wReserved[1] == VER_NT_WORKSTATION) + #else + if (osvi.wProductType == VER_NT_WORKSTATION) + #endif // WINVER < 0x0500 + { + if (osvi.dwMajorVersion == 4) + _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax); + #if WINVER < 0x0500 + else if (osvi.wReserved[0] & VER_SUITE_PERSONAL) + #else + else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Home Edition "), cntMax); + #if WINVER < 0x0500 + else if (osvi.wReserved[0] & VER_SUITE_EMBEDDEDNT) + #else + else if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Embedded "), cntMax); + else + _tcsncat(szVersion, _T("Professional "), cntMax); + } + // Test for the server type. + #if WINVER < 0x0500 + else if (osvi.wReserved[1] == VER_NT_SERVER) + #else + else if (osvi.wProductType == VER_NT_SERVER) + #endif // WINVER < 0x0500 + { + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + { + #if WINVER < 0x0500 + if (osvi.wReserved[0] & VER_SUITE_DATACENTER) + #else + if (osvi.wSuiteMask & VER_SUITE_DATACENTER) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Datacenter Edition "), cntMax); + #if WINVER < 0x0500 + else if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) + #else + else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Enterprise Edition "), cntMax); + #if WINVER < 0x0500 + else if (osvi.wReserved[0] == VER_SUITE_BLADE) + #else + else if (osvi.wSuiteMask == VER_SUITE_BLADE) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Web Edition "), cntMax); + else + _tcsncat(szVersion, _T("Standard Edition "), cntMax); + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + { + #if WINVER < 0x0500 + if (osvi.wReserved[0] & VER_SUITE_DATACENTER) + #else + if (osvi.wSuiteMask & VER_SUITE_DATACENTER) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Datacenter Server "), cntMax); + #if WINVER < 0x0500 + else if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) + #else + else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Advanced Server "), cntMax); + else + _tcsncat(szVersion, _T("Server "), cntMax); + } + else // Windows NT 4.0 + { + #if WINVER < 0x0500 + if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) + #else + if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) + #endif // WINVER < 0x0500 + _tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax); + else + _tcsncat(szVersion, _T("Server 4.0 "), cntMax); + } + } + } + // Display service pack (if any) and build number. + if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0) + { + HKEY hKey; + LONG lRet; + + // Test for SP6 versus SP6a. + lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey); + if (lRet == ERROR_SUCCESS) + { + _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"), + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + } + else // Windows NT 4.0 prior to SP6a + { + _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), + osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + } + ::RegCloseKey(hKey); + } + else // Windows NT 3.51 and earlier or Windows 2000 and later + { + if (!_tcslen(osvi.szCSDVersion)) + _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"), + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + else + _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), + osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + } + break; + default: + _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), + osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + break; + } + + return TRUE; +} + +void WheatyExceptionReport::PrintSystemInfo() +{ + SYSTEM_INFO SystemInfo; + ::GetSystemInfo(&SystemInfo); + + MEMORYSTATUS MemoryStatus; + MemoryStatus.dwLength = sizeof (MEMORYSTATUS); + ::GlobalMemoryStatus(&MemoryStatus); + TCHAR sString[1024]; + _tprintf(_T("//=====================================================\r\n")); + if (_GetProcessorName(sString, countof(sString))) + _tprintf(_T("*** Hardware ***\r\nProcessor: %s\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"), + sString, SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400); + else + _tprintf(_T("*** Hardware ***\r\nProcessor: <unknown>\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"), + SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400); + + if (_GetWindowsVersion(sString, countof(sString))) + _tprintf(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString); + else + _tprintf(_T("\r\n*** Operation System:\r\n<unknown>\r\n")); +} + +//=========================================================================== +void WheatyExceptionReport::printTracesForAllThreads() +{ + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + + DWORD dwOwnerPID = GetCurrentProcessId(); + m_hProcess = GetCurrentProcess(); + // Take a snapshot of all running threads + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) + return; + + // Fill in the size of the structure before using it. + te32.dwSize = sizeof(THREADENTRY32); + + // Retrieve information about the first thread, + // and exit if unsuccessful + if (!Thread32First(hThreadSnap, &te32)) + { + CloseHandle(hThreadSnap); // Must clean up the + // snapshot object! + return; + } + + // Now walk the thread list of the system, + // and display information about each thread + // associated with the specified process + do + { + if (te32.th32OwnerProcessID == dwOwnerPID) + { + CONTEXT context; + context.ContextFlags = 0xffffffff; + HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,false, te32.th32ThreadID); + if (threadHandle && GetThreadContext(threadHandle, &context)) + { + WriteStackDetails(&context, false, threadHandle); + } + CloseHandle(threadHandle); + } + } while(Thread32Next(hThreadSnap, &te32)); + +// Don't forget to clean up the snapshot object. + CloseHandle(hThreadSnap); +} + +//=========================================================================== +// Open the report file, and write the desired information to it. Called by +// WheatyUnhandledExceptionFilter +//=========================================================================== +void WheatyExceptionReport::GenerateExceptionReport( +PEXCEPTION_POINTERS pExceptionInfo) +{ + SYSTEMTIME systime; + GetLocalTime(&systime); + + // Start out with a banner + _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); + _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); + PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; + + PrintSystemInfo(); + // First print information about the type of fault + _tprintf(_T("\r\n//=====================================================\r\n")); + _tprintf(_T("Exception code: %08X %s\r\n"), + pExceptionRecord->ExceptionCode, + GetExceptionString(pExceptionRecord->ExceptionCode)); + + // Now print information about where the fault occured + TCHAR szFaultingModule[MAX_PATH]; + DWORD section; + DWORD_PTR offset; + GetLogicalAddress(pExceptionRecord->ExceptionAddress, + szFaultingModule, + sizeof(szFaultingModule), + section, offset); + +#ifdef _M_IX86 + _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); +#endif +#ifdef _M_X64 + _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); +#endif + + PCONTEXT pCtx = pExceptionInfo->ContextRecord; + + // Show the registers + #ifdef _M_IX86 // X86 Only! + _tprintf(_T("\r\nRegisters:\r\n")); + + _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") + ,pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, + pCtx->Esi, pCtx->Edi); + + _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); + _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), + pCtx->SegSs, pCtx->Esp, pCtx->Ebp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); + #endif + + #ifdef _M_X64 + _tprintf(_T("\r\nRegisters:\r\n")); + _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") + _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") + ,pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, + pCtx->Rsi, pCtx->Rdi ,pCtx->R9,pCtx->R10,pCtx->R11,pCtx->R12,pCtx->R13,pCtx->R14,pCtx->R15); + _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); + _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), + pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); + #endif + + SymSetOptions(SYMOPT_DEFERRED_LOADS); + + // Initialize DbgHelp + if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) + { + _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), + ErrorMessage(GetLastError())); + } + + CONTEXT trashableContext = *pCtx; + + WriteStackDetails(&trashableContext, false, NULL); + printTracesForAllThreads(); + +// #ifdef _M_IX86 // X86 Only! + + _tprintf(_T("========================\r\n")); + _tprintf(_T("Local Variables And Parameters\r\n")); + + trashableContext = *pCtx; + WriteStackDetails(&trashableContext, true, NULL); + + _tprintf(_T("========================\r\n")); + _tprintf(_T("Global Variables\r\n")); + + SymEnumSymbols(GetCurrentProcess(), + (DWORD64)GetModuleHandle(szFaultingModule), + 0, EnumerateSymbolsCallback, 0); + // #endif // X86 Only! + + SymCleanup(GetCurrentProcess()); + + _tprintf(_T("\r\n")); +} + +//====================================================================== +// Given an exception code, returns a pointer to a static string with a +// description of the exception +//====================================================================== +LPTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode) +{ + #define EXCEPTION(x) case EXCEPTION_##x: return _T(#x); + + switch (dwCode) + { + EXCEPTION(ACCESS_VIOLATION) + EXCEPTION(DATATYPE_MISALIGNMENT) + EXCEPTION(BREAKPOINT) + EXCEPTION(SINGLE_STEP) + EXCEPTION(ARRAY_BOUNDS_EXCEEDED) + EXCEPTION(FLT_DENORMAL_OPERAND) + EXCEPTION(FLT_DIVIDE_BY_ZERO) + EXCEPTION(FLT_INEXACT_RESULT) + EXCEPTION(FLT_INVALID_OPERATION) + EXCEPTION(FLT_OVERFLOW) + EXCEPTION(FLT_STACK_CHECK) + EXCEPTION(FLT_UNDERFLOW) + EXCEPTION(INT_DIVIDE_BY_ZERO) + EXCEPTION(INT_OVERFLOW) + EXCEPTION(PRIV_INSTRUCTION) + EXCEPTION(IN_PAGE_ERROR) + EXCEPTION(ILLEGAL_INSTRUCTION) + EXCEPTION(NONCONTINUABLE_EXCEPTION) + EXCEPTION(STACK_OVERFLOW) + EXCEPTION(INVALID_DISPOSITION) + EXCEPTION(GUARD_PAGE) + EXCEPTION(INVALID_HANDLE) + } + + // If not one of the "known" exceptions, try to get the string + // from NTDLL.DLL's message table. + + static TCHAR szBuffer[512] = { 0 }; + + FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, + GetModuleHandle(_T("NTDLL.DLL")), + dwCode, 0, szBuffer, sizeof(szBuffer), 0); + + return szBuffer; +} + +//============================================================================= +// Given a linear address, locates the module, section, and offset containing +// that address. +// +// Note: the szModule paramater buffer is an output buffer of length specified +// by the len parameter (in characters!) +//============================================================================= +BOOL WheatyExceptionReport::GetLogicalAddress( +PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset) +{ + MEMORY_BASIC_INFORMATION mbi; + + if (!VirtualQuery(addr, &mbi, sizeof(mbi))) + return FALSE; + + DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase; + + if (!GetModuleFileName((HMODULE)hMod, szModule, len)) + return FALSE; + + // Point to the DOS header in memory + PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod; + + // From the DOS header, find the NT (PE) header + PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew)); + + PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr); + + DWORD_PTR rva = (DWORD_PTR)addr - hMod; // RVA is offset from module load address + + // Iterate through the section table, looking for the one that encompasses + // the linear address. + for (unsigned i = 0; + i < pNtHdr->FileHeader.NumberOfSections; + i++, pSection++) + { + DWORD_PTR sectionStart = pSection->VirtualAddress; + DWORD_PTR sectionEnd = sectionStart + + DWORD_PTR(max(pSection->SizeOfRawData, pSection->Misc.VirtualSize)); + + // Is the address in this section??? + if ((rva >= sectionStart) && (rva <= sectionEnd)) + { + // Yes, address is in the section. Calculate section and offset, + // and store in the "section" & "offset" params, which were + // passed by reference. + section = i+1; + offset = rva - sectionStart; + return TRUE; + } + } + + return FALSE; // Should never get here! +} + +// It contains SYMBOL_INFO structure plus additional +// space for the name of the symbol +struct CSymbolInfoPackage : public SYMBOL_INFO_PACKAGE +{ + CSymbolInfoPackage() + { + si.SizeOfStruct = sizeof(SYMBOL_INFO); + si.MaxNameLen = sizeof(name); + } +}; + +//============================================================ +// Walks the stack, and writes the results to the report file +//============================================================ +void WheatyExceptionReport::WriteStackDetails( +PCONTEXT pContext, +bool bWriteVariables, HANDLE pThreadHandle) // true if local/params should be output +{ + _tprintf(_T("\r\nCall stack:\r\n")); + + _tprintf(_T("Address Frame Function SourceFile\r\n")); + + DWORD dwMachineType = 0; + // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag + + STACKFRAME64 sf; + memset(&sf, 0, sizeof(sf)); + + #ifdef _M_IX86 + // Initialize the STACKFRAME structure for the first call. This is only + // necessary for Intel CPUs, and isn't mentioned in the documentation. + sf.AddrPC.Offset = pContext->Eip; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrStack.Offset = pContext->Esp; + sf.AddrStack.Mode = AddrModeFlat; + sf.AddrFrame.Offset = pContext->Ebp; + sf.AddrFrame.Mode = AddrModeFlat; + + dwMachineType = IMAGE_FILE_MACHINE_I386; + #endif + +#ifdef _M_X64 + sf.AddrPC.Offset = pContext->Rip; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrStack.Offset = pContext->Rsp; + sf.AddrStack.Mode = AddrModeFlat; + sf.AddrFrame.Offset = pContext->Rbp; + sf.AddrFrame.Mode = AddrModeFlat; + dwMachineType = IMAGE_FILE_MACHINE_AMD64; +#endif + + while (1) + { + // Get the next stack frame + if (! StackWalk64(dwMachineType, + m_hProcess, + pThreadHandle != NULL ? pThreadHandle : GetCurrentThread(), + &sf, + pContext, + 0, + SymFunctionTableAccess64, + SymGetModuleBase64, + 0)) + break; + if (0 == sf.AddrFrame.Offset) // Basic sanity check to make sure + break; // the frame is OK. Bail if not. +#ifdef _M_IX86 + _tprintf(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); +#endif +#ifdef _M_X64 + _tprintf(_T("%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset); +#endif + + DWORD64 symDisplacement = 0; // Displacement of the input address, + // relative to the start of the symbol + + // Get the name of the function for this stack frame entry + CSymbolInfoPackage sip; + if (SymFromAddr( + m_hProcess, // Process handle of the current process + sf.AddrPC.Offset, // Symbol address + &symDisplacement, // Address of the variable that will receive the displacement + &sip.si)) // Address of the SYMBOL_INFO structure (inside "sip" object) + { + _tprintf(_T("%hs+%I64X"), sip.si.Name, symDisplacement); + + } + else // No symbol found. Print out the logical address instead. + { + TCHAR szModule[MAX_PATH] = _T(""); + DWORD section = 0; + DWORD_PTR offset = 0; + + GetLogicalAddress((PVOID)sf.AddrPC.Offset, + szModule, sizeof(szModule), section, offset); +#ifdef _M_IX86 + _tprintf(_T("%04X:%08X %s"), section, offset, szModule); +#endif +#ifdef _M_X64 + _tprintf(_T("%04X:%016I64X %s"), section, offset, szModule); +#endif + } + + // Get the source line for this stack frame entry + IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE) }; + DWORD dwLineDisplacement; + if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset, + &dwLineDisplacement, &lineInfo)) + { + _tprintf(_T(" %s line %u"),lineInfo.FileName,lineInfo.LineNumber); + } + + _tprintf(_T("\r\n")); + + // Write out the variables, if desired + if (bWriteVariables) + { + // Use SymSetContext to get just the locals/params for this frame + IMAGEHLP_STACK_FRAME imagehlpStackFrame; + imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset; + SymSetContext(m_hProcess, &imagehlpStackFrame, 0); + + // Enumerate the locals/parameters + SymEnumSymbols(m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf); + + _tprintf(_T("\r\n")); + } + } + +} + +////////////////////////////////////////////////////////////////////////////// +// The function invoked by SymEnumSymbols +////////////////////////////////////////////////////////////////////////////// + +BOOL CALLBACK +WheatyExceptionReport::EnumerateSymbolsCallback( +PSYMBOL_INFO pSymInfo, +ULONG SymbolSize, +PVOID UserContext) +{ + + char szBuffer[2048]; + + __try + { + if (FormatSymbolValue(pSymInfo, (STACKFRAME*)UserContext, + szBuffer, sizeof(szBuffer))) + _tprintf(_T("\t%s\r\n"), szBuffer); + } + __except(1) + { + _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name); + } + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////// +// Given a SYMBOL_INFO representing a particular variable, displays its +// contents. If it's a user defined type, display the members and their +// values. +////////////////////////////////////////////////////////////////////////////// +bool WheatyExceptionReport::FormatSymbolValue( +PSYMBOL_INFO pSym, +STACKFRAME * sf, +char * pszBuffer, +unsigned cbBuffer) +{ + char * pszCurrBuffer = pszBuffer; + + // Indicate if the variable is a local or parameter + if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) + pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter "); + else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) + pszCurrBuffer += sprintf(pszCurrBuffer, "Local "); + + // If it's a function, don't do anything. + if (pSym->Tag == 5) // SymTagFunction from CVCONST.H from the DIA SDK + return false; + + DWORD_PTR pVariable = 0; // Will point to the variable's data in memory + + if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE) + { + // if (pSym->Register == 8) // EBP is the value 8 (in DBGHELP 5.1) + { // This may change!!! + pVariable = sf->AddrFrame.Offset; + pVariable += (DWORD_PTR)pSym->Address; + } + // else + // return false; + } + else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER) + { + return false; // Don't try to report register variable + } + else + { + pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable + } + + // Determine if the variable is a user defined type (UDT). IF so, bHandled + // will return true. + bool bHandled; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer,pSym->ModBase, pSym->TypeIndex, + 0, pVariable, bHandled, pSym->Name); + + if (!bHandled) + { + // The symbol wasn't a UDT, so do basic, stupid formatting of the + // variable. Based on the size, we're assuming it's a char, WORD, or + // DWORD. + BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase); + pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + + // Emit the variable name + pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name); + + pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size, + (PVOID)pVariable); + } + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// If it's a user defined type (UDT), recurse through its members until we're +// at fundamental types. When he hit fundamental types, return +// bHandled = false, so that FormatSymbolValue() will format them. +////////////////////////////////////////////////////////////////////////////// +char * WheatyExceptionReport::DumpTypeIndex( +char * pszCurrBuffer, +DWORD64 modBase, +DWORD dwTypeIndex, +unsigned nestingLevel, +DWORD_PTR offset, +bool & bHandled, +char* Name) +{ + bHandled = false; + + // Get the name of the symbol. This will either be a Type name (if a UDT), + // or the structure member name. + WCHAR * pwszTypeName; + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME, + &pwszTypeName)) + { + pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); + LocalFree(pwszTypeName); + } + + // Determine how many children this type has. + DWORD dwChildrenCount = 0; + SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, + &dwChildrenCount); + + if (!dwChildrenCount) // If no children, we're done + return pszCurrBuffer; + + // Prepare to get an array of "TypeIds", representing each of the children. + // SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a + // TI_FINDCHILDREN_PARAMS struct has. Use derivation to accomplish this. + struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS + { + ULONG MoreChildIds[1024]; + FINDCHILDREN(){Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);} + } children; + + children.Count = dwChildrenCount; + children.Start= 0; + + // Get the array of TypeIds, one for each child type + if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN, + &children)) + { + return pszCurrBuffer; + } + + // Append a line feed + pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + + // Iterate through each of the children + for (unsigned i = 0; i < dwChildrenCount; i++) + { + // Add appropriate indentation level (since this routine is recursive) + for (unsigned j = 0; j <= nestingLevel+1; j++) + pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + + // Recurse for each of the child types + bool bHandled2; + BasicType basicType = GetBasicType(children.ChildId[i], modBase); + pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, + children.ChildId[i], nestingLevel+1, + offset, bHandled2, ""/*Name */); + + // If the child wasn't a UDT, format it appropriately + if (!bHandled2) + { + // Get the offset of the child member, relative to its parent + DWORD dwMemberOffset; + SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], + TI_GET_OFFSET, &dwMemberOffset); + + // Get the real "TypeId" of the child. We need this for the + // SymGetTypeInfo(TI_GET_TYPEID) call below. + DWORD typeId; + SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], + TI_GET_TYPEID, &typeId); + + // Get the size of the child member + ULONG64 length; + SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH,&length); + + // Calculate the address of the member + DWORD_PTR dwFinalOffset = offset + dwMemberOffset; + + // BasicType basicType = GetBasicType(children.ChildId[i], modBase); + // + // pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + // + // Emit the variable name + // pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", Name); + + pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, + length, (PVOID)dwFinalOffset); + + pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + } + } + + bHandled = true; + return pszCurrBuffer; +} + +char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, +BasicType basicType, +DWORD64 length, +PVOID pAddress) +{ + // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!) + if (length == 1) + pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress); + else if (length == 2) + pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress); + else if (length == 4) + { + if (basicType == btFloat) + { + pszCurrBuffer += sprintf(pszCurrBuffer," = %f", *(PFLOAT)pAddress); + } + else if (basicType == btChar) + { + if (!IsBadStringPtr(*(PSTR*)pAddress, 32)) + { + pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"", + *(PDWORD)pAddress); + } + else + pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", + *(PDWORD)pAddress); + } + else + pszCurrBuffer += sprintf(pszCurrBuffer," = %X", *(PDWORD)pAddress); + } + else if (length == 8) + { + if (basicType == btFloat) + { + pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf", + *(double *)pAddress); + } + else + pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", + *(DWORD64*)pAddress); + } + + return pszCurrBuffer; +} + +BasicType +WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) +{ + BasicType basicType; + if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, + TI_GET_BASETYPE, &basicType)) + { + return basicType; + } + + // Get the real "TypeId" of the child. We need this for the + // SymGetTypeInfo(TI_GET_TYPEID) call below. + DWORD typeId; + if (SymGetTypeInfo(m_hProcess,modBase, typeIndex, TI_GET_TYPEID, &typeId)) + { + if (SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_BASETYPE, + &basicType)) + { + return basicType; + } + } + + return btNoType; +} + +//============================================================================ +// Helper function that writes to the report file, and allows the user to use +// printf style formating +//============================================================================ +int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) +{ + TCHAR szBuff[1024]; + int retValue; + DWORD cbWritten; + va_list argptr; + + va_start(argptr, format); + retValue = vsprintf(szBuff, format, argptr); + va_end(argptr); + + WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + + return retValue; +} + diff --git a/src/server/shared/WheatyExceptionReport.h b/src/server/shared/WheatyExceptionReport.h new file mode 100644 index 00000000000..33fb4bc5b0e --- /dev/null +++ b/src/server/shared/WheatyExceptionReport.h @@ -0,0 +1,118 @@ +#ifndef _WHEATYEXCEPTIONREPORT_ +#define _WHEATYEXCEPTIONREPORT_ + +#include <dbghelp.h> + +#if _MSC_VER < 1400 +# define countof(array) (sizeof(array) / sizeof(array[0])) +#else +# include <stdlib.h> +# define countof _countof +#endif // _MSC_VER < 1400 + +enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK +{ + btNoType = 0, + btVoid = 1, + btChar = 2, + btWChar = 3, + btInt = 6, + btUInt = 7, + btFloat = 8, + btBCD = 9, + btBool = 10, + btLong = 13, + btULong = 14, + btCurrency = 25, + btDate = 26, + btVariant = 27, + btComplex = 28, + btBit = 29, + btBSTR = 30, + btHresult = 31 +}; + +const char* const rgBaseType[] = +{ + " <user defined> ", // btNoType = 0, + " void ", // btVoid = 1, + " char* ", // btChar = 2, + " wchar_t* ", // btWChar = 3, + " signed char ", + " unsigned char ", + " int ", // btInt = 6, + " unsigned int ", // btUInt = 7, + " float ", // btFloat = 8, + " <BCD> ", // btBCD = 9, + " bool ", // btBool = 10, + " short ", + " unsigned short ", + " long ", // btLong = 13, + " unsigned long ", // btULong = 14, + " __int8 ", + " __int16 ", + " __int32 ", + " __int64 ", + " __int128 ", + " unsigned __int8 ", + " unsigned __int16 ", + " unsigned __int32 ", + " unsigned __int64 ", + " unsigned __int128 ", + " <currency> ", // btCurrency = 25, + " <date> ", // btDate = 26, + " VARIANT ", // btVariant = 27, + " <complex> ", // btComplex = 28, + " <bit> ", // btBit = 29, + " BSTR ", // btBSTR = 30, + " HRESULT " // btHresult = 31 +}; + +class WheatyExceptionReport +{ + public: + + WheatyExceptionReport(); + ~WheatyExceptionReport(); + + // entry point where control comes on an unhandled exception + static LONG WINAPI WheatyUnhandledExceptionFilter( + PEXCEPTION_POINTERS pExceptionInfo); + + static void printTracesForAllThreads(); + private: + // where report info is extracted and generated + static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo); + static void PrintSystemInfo(); + static BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax); + static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount); + + // Helper functions + static LPTSTR GetExceptionString(DWORD dwCode); + static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, + DWORD& section, DWORD_PTR& offset); + + static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle); + + static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO,ULONG, PVOID); + + static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME *, char * pszBuffer, unsigned cbBuffer); + + static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool & , char*); + + static char * FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress); + + static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase); + + static int __cdecl _tprintf(const TCHAR * format, ...); + + // Variables used by the class + static TCHAR m_szLogFileName[MAX_PATH]; + static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter; + static HANDLE m_hReportFile; + static HANDLE m_hProcess; +}; + +extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class +#endif //WheatyExceptionReport + diff --git a/src/server/shared/WorldPacket.h b/src/server/shared/WorldPacket.h new file mode 100644 index 00000000000..d708959f91d --- /dev/null +++ b/src/server/shared/WorldPacket.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYCORE_WORLDPACKET_H +#define TRINITYCORE_WORLDPACKET_H + +#include "Common.h" +#include "ByteBuffer.h" + +class WorldPacket : public ByteBuffer +{ + public: + // just container for later use + WorldPacket() : ByteBuffer(0), m_opcode(0) + { + } + explicit WorldPacket(uint16 opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { } + // copy constructor + WorldPacket(const WorldPacket &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode) + { + } + + void Initialize(uint16 opcode, size_t newres=200) + { + clear(); + _storage.reserve(newres); + m_opcode = opcode; + } + + uint16 GetOpcode() const { return m_opcode; } + void SetOpcode(uint16 opcode) { m_opcode = opcode; } + + protected: + uint16 m_opcode; +}; +#endif + diff --git a/src/server/shared/vmap/BIH.cpp b/src/server/shared/vmap/BIH.cpp new file mode 100644 index 00000000000..4bd6b3c701e --- /dev/null +++ b/src/server/shared/vmap/BIH.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "BIH.h" + +void BIH::buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats) +{ + // create space for the first node + tempTree.push_back(3 << 30); // dummy leaf + tempTree.insert(tempTree.end(), 2, 0); + //tempTree.add(0); + + // seed bbox + AABound gridBox = { bounds.low(), bounds.high() }; + AABound nodeBox = gridBox; + // seed subdivide function + subdivide(0, dat.numPrims - 1, tempTree, dat, gridBox, nodeBox, 0, 1, stats); +} + +void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats) +{ + if ((right - left + 1) <= dat.maxPrims || depth >= MAX_STACK_SIZE) + { + // write leaf node + stats.updateLeaf(depth, right - left + 1); + createNode(tempTree, nodeIndex, left, right); + return; + } + // calculate extents + int axis = -1, prevAxis, rightOrig; + float clipL = G3D::fnan(), clipR = G3D::fnan(), prevClip = G3D::fnan(); + float split = G3D::fnan(), prevSplit; + bool wasLeft = true; + while (true) + { + prevAxis = axis; + prevSplit = split; + // perform quick consistency checks + Vector3 d( gridBox.hi - gridBox.lo ); + if (d.x < 0 || d.y < 0 || d.z < 0) + throw std::logic_error("negative node extents"); + for (int i = 0; i < 3; i++) + { + if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i]) + { + //UI.printError(Module.ACCEL, "Reached tree area in error - discarding node with: %d objects", right - left + 1); + throw std::logic_error("invalid node overlap"); + } + } + // find longest axis + axis = d.primaryAxis(); + split = 0.5f * (gridBox.lo[axis] + gridBox.hi[axis]); + // partition L/R subsets + clipL = -G3D::inf(); + clipR = G3D::inf(); + rightOrig = right; // save this for later + float nodeL = G3D::inf(); + float nodeR = -G3D::inf(); + for (int i = left; i <= right;) + { + int obj = dat.indices[i]; + float minb = dat.primBound[obj].low()[axis]; + float maxb = dat.primBound[obj].high()[axis]; + float center = (minb + maxb) * 0.5f; + if (center <= split) + { + // stay left + i++; + if (clipL < maxb) + clipL = maxb; + } + else + { + // move to the right most + int t = dat.indices[i]; + dat.indices[i] = dat.indices[right]; + dat.indices[right] = t; + right--; + if (clipR > minb) + clipR = minb; + } + nodeL = std::min(nodeL, minb); + nodeR = std::max(nodeR, maxb); + } + // check for empty space + if (nodeL > nodeBox.lo[axis] && nodeR < nodeBox.hi[axis]) + { + float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[axis]; + float nodeNewW = nodeR - nodeL; + // node box is too big compare to space occupied by primitives? + if (1.3f * nodeNewW < nodeBoxW) + { + stats.updateBVH2(); + int nextIndex = tempTree.size(); + // allocate child + tempTree.push_back(0); + tempTree.push_back(0); + tempTree.push_back(0); + // write bvh2 clip node + stats.updateInner(); + tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex; + tempTree[nodeIndex + 1] = floatToRawIntBits(nodeL); + tempTree[nodeIndex + 2] = floatToRawIntBits(nodeR); + // update nodebox and recurse + nodeBox.lo[axis] = nodeL; + nodeBox.hi[axis] = nodeR; + subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex, depth + 1, stats); + return; + } + } + // ensure we are making progress in the subdivision + if (right == rightOrig) + { + // all left + if (prevAxis == axis && prevSplit == split) { + // we are stuck here - create a leaf + stats.updateLeaf(depth, right - left + 1); + createNode(tempTree, nodeIndex, left, right); + return; + } + if (clipL <= split) { + // keep looping on left half + gridBox.hi[axis] = split; + prevClip = clipL; + wasLeft = true; + continue; + } + gridBox.hi[axis] = split; + prevClip = G3D::fnan(); + } + else if (left > right) + { + // all right + if (prevAxis == axis && prevSplit == split) { + // we are stuck here - create a leaf + stats.updateLeaf(depth, right - left + 1); + createNode(tempTree, nodeIndex, left, right); + return; + } + right = rightOrig; + if (clipR >= split) { + // keep looping on right half + gridBox.lo[axis] = split; + prevClip = clipR; + wasLeft = false; + continue; + } + gridBox.lo[axis] = split; + prevClip = G3D::fnan(); + } + else + { + // we are actually splitting stuff + if (prevAxis != -1 && !isnan(prevClip)) + { + // second time through - lets create the previous split + // since it produced empty space + int nextIndex = tempTree.size(); + // allocate child node + tempTree.push_back(0); + tempTree.push_back(0); + tempTree.push_back(0); + if (wasLeft) { + // create a node with a left child + // write leaf node + stats.updateInner(); + tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex; + tempTree[nodeIndex + 1] = floatToRawIntBits(prevClip); + tempTree[nodeIndex + 2] = floatToRawIntBits(G3D::inf()); + } else { + // create a node with a right child + // write leaf node + stats.updateInner(); + tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3); + tempTree[nodeIndex + 1] = floatToRawIntBits(-G3D::inf()); + tempTree[nodeIndex + 2] = floatToRawIntBits(prevClip); + } + // count stats for the unused leaf + depth++; + stats.updateLeaf(depth, 0); + // now we keep going as we are, with a new nodeIndex: + nodeIndex = nextIndex; + } + break; + } + } + // compute index of child nodes + int nextIndex = tempTree.size(); + // allocate left node + int nl = right - left + 1; + int nr = rightOrig - (right + 1) + 1; + if (nl > 0) { + tempTree.push_back(0); + tempTree.push_back(0); + tempTree.push_back(0); + } else + nextIndex -= 3; + // allocate right node + if (nr > 0) { + tempTree.push_back(0); + tempTree.push_back(0); + tempTree.push_back(0); + } + // write leaf node + stats.updateInner(); + tempTree[nodeIndex + 0] = (axis << 30) | nextIndex; + tempTree[nodeIndex + 1] = floatToRawIntBits(clipL); + tempTree[nodeIndex + 2] = floatToRawIntBits(clipR); + // prepare L/R child boxes + AABound gridBoxL(gridBox), gridBoxR(gridBox); + AABound nodeBoxL(nodeBox), nodeBoxR(nodeBox); + gridBoxL.hi[axis] = gridBoxR.lo[axis] = split; + nodeBoxL.hi[axis] = clipL; + nodeBoxR.lo[axis] = clipR; + // recurse + if (nl > 0) + subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats); + else + stats.updateLeaf(depth + 1, 0); + if (nr > 0) + subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats); + else + stats.updateLeaf(depth + 1, 0); +} + +bool BIH::writeToFile(FILE *wf) const +{ + uint32 treeSize = tree.size(); + uint32 check=0, count=0; + check += fwrite(&bounds.low(), sizeof(float), 3, wf); + check += fwrite(&bounds.high(), sizeof(float), 3, wf); + check += fwrite(&treeSize, sizeof(uint32), 1, wf); + check += fwrite(&tree[0], sizeof(uint32), treeSize, wf); + count = objects.size(); + check += fwrite(&count, sizeof(uint32), 1, wf); + check += fwrite(&objects[0], sizeof(uint32), count, wf); + return check == (3 + 3 + 2 + treeSize + count); +} + +bool BIH::readFromFile(FILE *rf) +{ + uint32 treeSize; + Vector3 lo, hi; + uint32 check=0, count=0; + check += fread(&lo, sizeof(float), 3, rf); + check += fread(&hi, sizeof(float), 3, rf); + bounds = AABox(lo, hi); + check += fread(&treeSize, sizeof(uint32), 1, rf); + tree.resize(treeSize); + check += fread(&tree[0], sizeof(uint32), treeSize, rf); + check += fread(&count, sizeof(uint32), 1, rf); + objects.resize(count); // = new uint32[nObjects]; + check += fread(&objects[0], sizeof(uint32), count, rf); + return check == (3 + 3 + 2 + treeSize + count); +} + +void BIH::BuildStats::updateLeaf(int depth, int n) +{ + numLeaves++; + minDepth = std::min(depth, minDepth); + maxDepth = std::max(depth, maxDepth); + sumDepth += depth; + minObjects = std::min(n, minObjects); + maxObjects = std::max(n, maxObjects); + sumObjects += n; + int nl = std::min(n, 5); + ++numLeavesN[nl]; +} + +void BIH::BuildStats::printStats() +{ + printf("Tree stats:\n"); + printf(" * Nodes: %d\n", numNodes); + printf(" * Leaves: %d\n", numLeaves); + printf(" * Objects: min %d\n", minObjects); + printf(" avg %.2f\n", (float) sumObjects / numLeaves); + printf(" avg(n>0) %.2f\n", (float) sumObjects / (numLeaves - numLeavesN[0])); + printf(" max %d\n", maxObjects); + printf(" * Depth: min %d\n", minDepth); + printf(" avg %.2f\n", (float) sumDepth / numLeaves); + printf(" max %d\n", maxDepth); + printf(" * Leaves w/: N=0 %3d%%\n", 100 * numLeavesN[0] / numLeaves); + printf(" N=1 %3d%%\n", 100 * numLeavesN[1] / numLeaves); + printf(" N=2 %3d%%\n", 100 * numLeavesN[2] / numLeaves); + printf(" N=3 %3d%%\n", 100 * numLeavesN[3] / numLeaves); + printf(" N=4 %3d%%\n", 100 * numLeavesN[4] / numLeaves); + printf(" N>4 %3d%%\n", 100 * numLeavesN[5] / numLeaves); + printf(" * BVH2 nodes: %d (%3d%%)\n", numBVH2, 100 * numBVH2 / (numNodes + numLeaves - 2 * numBVH2)); +} diff --git a/src/server/shared/vmap/BIH.h b/src/server/shared/vmap/BIH.h new file mode 100644 index 00000000000..15ae90c23eb --- /dev/null +++ b/src/server/shared/vmap/BIH.h @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _BIH_H +#define _BIH_H + +#include <G3D/Vector3.h> +#include <G3D/Ray.h> +#include <G3D/AABox.h> + +#include <Platform/Define.h> + +#include <stdexcept> +#include <vector> +#include <algorithm> +#include <limits> +#include <cmath> + +#define MAX_STACK_SIZE 64 + +#ifdef _MSC_VER + #define isnan(x) _isnan(x) +#endif + +using G3D::Vector3; +using G3D::AABox; +using G3D::Ray; + +static inline uint32 floatToRawIntBits(float f) +{ + union + { + uint32 ival; + float fval; + } temp; + temp.fval=f; + return temp.ival; +} + +static inline float intBitsToFloat(uint32 i) +{ + union + { + uint32 ival; + float fval; + } temp; + temp.ival=i; + return temp.fval; +} + +struct AABound +{ + Vector3 lo, hi; +}; + +/** Bounding Interval Hierarchy Class. + Building and Ray-Intersection functions based on BIH from + Sunflow, a Java Raytracer, released under MIT/X11 License + http://sunflow.sourceforge.net/ + Copyright (c) 2003-2007 Christopher Kulla +*/ + +class BIH +{ + public: + BIH() {}; + template< class T, class BoundsFunc > + void build(const std::vector<T> &primitives, BoundsFunc &getBounds, uint32 leafSize = 3, bool printStats=false) + { + if(primitives.size() == 0) + return; + buildData dat; + dat.maxPrims = leafSize; + dat.numPrims = primitives.size(); + dat.indices = new uint32[dat.numPrims]; + dat.primBound = new AABox[dat.numPrims]; + getBounds(primitives[0], bounds); + for (uint32 i=0; i<dat.numPrims; ++i) + { + dat.indices[i] = i; + AABox tb; + getBounds(primitives[i], dat.primBound[i]); + bounds.merge(dat.primBound[i]); + } + std::vector<uint32> tempTree; + BuildStats stats; + buildHierarchy(tempTree, dat, stats); + if (printStats) + stats.printStats(); + + objects.resize(dat.numPrims); + for (uint32 i=0; i<dat.numPrims; ++i) + objects[i] = dat.indices[i]; + //nObjects = dat.numPrims; + tree = tempTree; + delete[] dat.primBound; + delete[] dat.indices; + } + uint32 primCount() { return objects.size(); } + + template<typename RayCallback> + void intersectRay(const Ray &r, RayCallback& intersectCallback, float &maxDist, bool stopAtFirst=false) const + { + float intervalMin = 0.f; + float intervalMax = maxDist; + Vector3 org = r.origin(); + Vector3 dir = r.direction(); + Vector3 invDir; + float t1, t2; + for(int i=0; i<3; ++i) + { + invDir[i] = 1.f / dir[i]; + t1 = (bounds.low()[i] - org[i]) * invDir[i]; + t2 = (bounds.high()[i] - org[i]) * invDir[i]; + if (invDir[i] > 0) { + if (t1 > intervalMin) + intervalMin = t1; + if (t2 < intervalMax) + intervalMax = t2; + } else { + if (t2 > intervalMin) + intervalMin = t2; + if (t1 < intervalMax) + intervalMax = t1; + } + if (intervalMin > intervalMax) + return; + } + + uint32 offsetFront[3]; + uint32 offsetBack[3]; + uint32 offsetFront3[3]; + uint32 offsetBack3[3]; + // compute custom offsets from direction sign bit + + for(int i=0; i<3; ++i) + { + offsetFront[i] = floatToRawIntBits(dir[i]) >> 31; + offsetBack[i] = offsetFront[i] ^ 1; + offsetFront3[i] = offsetFront[i] * 3; + offsetBack3[i] = offsetBack[i] * 3; + + // avoid always adding 1 during the inner loop + ++offsetFront[i]; + ++offsetBack[i]; + } + + StackNode stack[MAX_STACK_SIZE]; + int stackPos = 0; + int node = 0; + + while (true) { + while (true) + { + uint32 tn = tree[node]; + uint32 axis = (tn & (3 << 30)) >> 30; + bool BVH2 = tn & (1 << 29); + int offset = tn & ~(7 << 29); + if (!BVH2) + { + if (axis < 3) + { + // "normal" interior node + float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis]; + float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis]; + // ray passes between clip zones + if (tf < intervalMin && tb > intervalMax) + break; + int back = offset + offsetBack3[axis]; + node = back; + // ray passes through far node only + if (tf < intervalMin) { + intervalMin = (tb >= intervalMin) ? tb : intervalMin; + continue; + } + node = offset + offsetFront3[axis]; // front + // ray passes through near node only + if (tb > intervalMax) { + intervalMax = (tf <= intervalMax) ? tf : intervalMax; + continue; + } + // ray passes through both nodes + // push back node + stack[stackPos].node = back; + stack[stackPos].tnear = (tb >= intervalMin) ? tb : intervalMin; + stack[stackPos].tfar = intervalMax; + stackPos++; + // update ray interval for front node + intervalMax = (tf <= intervalMax) ? tf : intervalMax; + continue; + } + else + { + // leaf - test some objects + int n = tree[node + 1]; + while (n > 0) { + bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirst); + if(stopAtFirst && hit) return; + --n; + ++offset; + } + break; + } + } + else + { + if (axis>2) + return; // should not happen + float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis]; + float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis]; + node = offset; + intervalMin = (tf >= intervalMin) ? tf : intervalMin; + intervalMax = (tb <= intervalMax) ? tb : intervalMax; + if (intervalMin > intervalMax) + break; + continue; + } + } // traversal loop + do + { + // stack is empty? + if (stackPos == 0) + return; + // move back up the stack + stackPos--; + intervalMin = stack[stackPos].tnear; + if (maxDist < intervalMin) + continue; + node = stack[stackPos].node; + intervalMax = stack[stackPos].tfar; + break; + } while (true); + } + } + + template<typename IsectCallback> + void intersectPoint(const Vector3 &p, IsectCallback& intersectCallback) const + { + if (!bounds.contains(p)) + return; + + StackNode stack[MAX_STACK_SIZE]; + int stackPos = 0; + int node = 0; + + while (true) { + while (true) + { + uint32 tn = tree[node]; + uint32 axis = (tn & (3 << 30)) >> 30; + bool BVH2 = tn & (1 << 29); + int offset = tn & ~(7 << 29); + if (!BVH2) + { + if (axis < 3) + { + // "normal" interior node + float tl = intBitsToFloat(tree[node + 1]); + float tr = intBitsToFloat(tree[node + 2]); + // point is between clip zones + if (tl < p[axis] && tr > p[axis]) + break; + int right = offset + 3; + node = right; + // point is in right node only + if (tl < p[axis]) { + continue; + } + node = offset; // left + // point is in left node only + if (tr > p[axis]) { + continue; + } + // point is in both nodes + // push back right node + stack[stackPos].node = right; + stackPos++; + continue; + } + else + { + // leaf - test some objects + int n = tree[node + 1]; + while (n > 0) { + intersectCallback(p, objects[offset]); // !!! + --n; + ++offset; + } + break; + } + } + else // BVH2 node (empty space cut off left and right) + { + if (axis>2) + return; // should not happen + float tl = intBitsToFloat(tree[node + 1]); + float tr = intBitsToFloat(tree[node + 2]); + node = offset; + if (tl > p[axis] || tr < p[axis]) + break; + continue; + } + } // traversal loop + + // stack is empty? + if (stackPos == 0) + return; + // move back up the stack + stackPos--; + node = stack[stackPos].node; + } + } + + bool writeToFile(FILE *wf) const; + bool readFromFile(FILE *rf); + + protected: + std::vector<uint32> tree; + std::vector<uint32> objects; + AABox bounds; + + struct buildData + { + uint32 *indices; + AABox *primBound; + uint32 numPrims; + int maxPrims; + }; + struct StackNode + { + uint32 node; + float tnear; + float tfar; + }; + + class BuildStats + { + private: + int numNodes; + int numLeaves; + int sumObjects; + int minObjects; + int maxObjects; + int sumDepth; + int minDepth; + int maxDepth; + int numLeavesN[6]; + int numBVH2; + + public: + BuildStats(): + numNodes(0), numLeaves(0), sumObjects(0), minObjects(0x0FFFFFFF), + maxObjects(0xFFFFFFFF), sumDepth(0), minDepth(0x0FFFFFFF), + maxDepth(0xFFFFFFFF), numBVH2(0) + { + for(int i=0; i<6; ++i) numLeavesN[i] = 0; + } + + void updateInner() { numNodes++; } + void updateBVH2() { numBVH2++; } + void updateLeaf(int depth, int n); + void printStats(); + }; + + void buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats); + + void createNode(std::vector<uint32> &tempTree, int nodeIndex, uint32 left, uint32 right) { + // write leaf node + tempTree[nodeIndex + 0] = (3 << 30) | left; + tempTree[nodeIndex + 1] = right - left + 1; + } + + void subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats); +}; + +#endif // _BIH_H diff --git a/src/server/shared/vmap/CMakeLists.txt b/src/server/shared/vmap/CMakeLists.txt new file mode 100644 index 00000000000..c930a0c5a25 --- /dev/null +++ b/src/server/shared/vmap/CMakeLists.txt @@ -0,0 +1,30 @@ + +########### next target ############### + +SET(vmaps_STAT_SRCS + BIH.h + BIH.cpp + IVMapManager.h + MapTree.cpp + MapTree.h + ModelInstance.cpp + ModelInstance.h + TileAssembler.cpp + TileAssembler.h + VMapDefinitions.h + VMapFactory.cpp + VMapFactory.h + VMapManager2.cpp + VMapManager2.h + VMapTools.h + WorldModel.cpp + WorldModel.h +) + +include_directories( + ${ACE_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/src/framework + ${CMAKE_SOURCE_DIR}/dep/include/g3dlite +) + +add_library(vmaps STATIC ${vmaps_STAT_SRCS}) diff --git a/src/server/shared/vmap/IVMapManager.h b/src/server/shared/vmap/IVMapManager.h new file mode 100644 index 00000000000..00629eb122c --- /dev/null +++ b/src/server/shared/vmap/IVMapManager.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _IVMAPMANAGER_H +#define _IVMAPMANAGER_H + +#include<string> +#include <Platform/Define.h> + +//=========================================================== + +/** +This is the minimum interface to the VMapMamager. +*/ + +namespace VMAP +{ + + enum VMAP_LOAD_RESULT + { + VMAP_LOAD_RESULT_ERROR, + VMAP_LOAD_RESULT_OK, + VMAP_LOAD_RESULT_IGNORED, + }; + + #define VMAP_INVALID_HEIGHT -100000.0f // for check + #define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case + + //=========================================================== + class IVMapManager + { + private: + bool iEnableLineOfSightCalc; + bool iEnableHeightCalc; + + public: + IVMapManager() : iEnableLineOfSightCalc(true), iEnableHeightCalc(true) {} + + virtual ~IVMapManager(void) {} + + virtual int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0; + + virtual bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0; + + virtual void unloadMap(unsigned int pMapId, int x, int y) = 0; + virtual void unloadMap(unsigned int pMapId) = 0; + + virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) = 0; + virtual float getHeight(unsigned int pMapId, float x, float y, float z) = 0; + /** + test if we hit an object. return true if we hit one. rx,ry,rz will hold the hit position or the dest position, if no intersection was found + return a position, that is pReduceDist closer to the origin + */ + virtual bool getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist) = 0; + /** + send debug commands + */ + virtual bool processCommand(char *pCommand)= 0; + + /** + Enable/disable LOS calculation + It is enabled by default. If it is enabled in mid game the maps have to loaded manualy + */ + void setEnableLineOfSightCalc(bool pVal) { iEnableLineOfSightCalc = pVal; } + /** + Enable/disable model height calculation + It is enabled by default. If it is enabled in mid game the maps have to loaded manualy + */ + void setEnableHeightCalc(bool pVal) { iEnableHeightCalc = pVal; } + + bool isLineOfSightCalcEnabled() const { return(iEnableLineOfSightCalc); } + bool isHeightCalcEnabled() const { return(iEnableHeightCalc); } + bool isMapLoadingEnabled() const { return(iEnableLineOfSightCalc || iEnableHeightCalc ); } + + virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const =0; + /** + Block maps from being used. + parameter: String of map ids. Delimiter = "," + e.g.: "0,1,530" + */ + virtual void preventMapsFromBeingUsed(const char* pMapIdString) =0; + /** + Query world model area info. + \param z gets adjusted to the ground height for which this are info is valid + */ + virtual bool getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const=0; + virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const=0; + }; + +} +#endif diff --git a/src/server/shared/vmap/MapTree.cpp b/src/server/shared/vmap/MapTree.cpp new file mode 100644 index 00000000000..8c77ee109f3 --- /dev/null +++ b/src/server/shared/vmap/MapTree.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MapTree.h" +#include "ModelInstance.h" +#include "VMapManager2.h" +#include "VMapDefinitions.h" + +#include <string> +#include <sstream> +#include <iomanip> + +using G3D::Vector3; + +namespace VMAP +{ + + class MapRayCallback + { + public: + MapRayCallback(ModelInstance *val): prims(val) {} + ModelInstance *prims; + bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool pStopAtFirstHit=true) + { + return prims[entry].intersectRay(ray, distance, pStopAtFirstHit); + //std::cout << "trying to intersect '" << entity->name << "'\n"; + } + }; + + class AreaInfoCallback + { + public: + AreaInfoCallback(ModelInstance *val): prims(val) {} + void operator()(const Vector3& point, uint32 entry) + { +#ifdef VMAP_DEBUG + std::cout << "trying to intersect '" << prims[entry].name << "'\n"; +#endif + prims[entry].intersectPoint(point, aInfo); + } + + ModelInstance *prims; + AreaInfo aInfo; + }; + + class LocationInfoCallback + { + public: + LocationInfoCallback(ModelInstance *val, LocationInfo &info): prims(val), locInfo(info), result(false) {} + void operator()(const Vector3& point, uint32 entry) + { +#ifdef VMAP_DEBUG + std::cout << "trying to intersect '" << prims[entry].name << "'\n"; +#endif + if (prims[entry].GetLocationInfo(point, locInfo)) + result = true; + } + + ModelInstance *prims; + LocationInfo &locInfo; + bool result; + }; + + + //========================================================= + + std::string StaticMapTree::getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY) + { + std::stringstream tilefilename; + tilefilename.fill('0'); + tilefilename << std::setw(3) << mapID << "_"; + //tilefilename << std::setw(2) << tileX << "_" << std::setw(2) << tileY << ".vmtile"; + tilefilename << std::setw(2) << tileY << "_" << std::setw(2) << tileX << ".vmtile"; + return tilefilename.str(); + } + + bool StaticMapTree::getAreaInfo(Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const + { + AreaInfoCallback intersectionCallBack(iTreeValues); + iTree.intersectPoint(pos, intersectionCallBack); + if (intersectionCallBack.aInfo.result) + { + flags = intersectionCallBack.aInfo.flags; + adtId = intersectionCallBack.aInfo.adtId; + rootId = intersectionCallBack.aInfo.rootId; + groupId = intersectionCallBack.aInfo.groupId; + pos.z = intersectionCallBack.aInfo.ground_Z; + return true; + } + return false; + } + + bool StaticMapTree::GetLocationInfo(const Vector3 &pos, LocationInfo &info) const + { + LocationInfoCallback intersectionCallBack(iTreeValues, info); + iTree.intersectPoint(pos, intersectionCallBack); + return intersectionCallBack.result; + } + + StaticMapTree::StaticMapTree(uint32 mapID, const std::string &basePath): + iMapID(mapID), /* iTree(0), */ iTreeValues(0), iBasePath(basePath) + { + if (iBasePath.length() > 0 && (iBasePath[iBasePath.length()-1] != '/' || iBasePath[iBasePath.length()-1] != '\\')) + { + iBasePath.append("/"); + } + } + + //========================================================= + //! Make sure to call unloadMap() to unregister acquired model references before destroying + StaticMapTree::~StaticMapTree() + { + delete[] iTreeValues; + } + + //========================================================= + /** + return dist to hit or inf() if no hit + */ + + float StaticMapTree::getIntersectionTime(const G3D::Ray& pRay, float pMaxDist, bool pStopAtFirstHit) const + { + float distance = pMaxDist; + MapRayCallback intersectionCallBack(iTreeValues); + iTree.intersectRay(pRay, intersectionCallBack, distance, pStopAtFirstHit); + return distance; + } + //========================================================= + + bool StaticMapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2) const + { + bool result = true; + float maxDist = (pos2 - pos1).magnitude(); + // prevent NaN values which can cause BIH intersection to enter infinite loop + if (maxDist < 1e-10f) + return true; + // direction with length of 1 + G3D::Ray ray = G3D::Ray::fromOriginAndDirection(pos1, (pos2 - pos1)/maxDist); + float resultDist = getIntersectionTime(ray, maxDist, true); + if (resultDist < maxDist) + { + result = false; + } + return result; + } + //========================================================= + /** + When moving from pos1 to pos2 check if we hit an object. Return true and the position if we hit one + Return the hit pos or the original dest pos + */ + + bool StaticMapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist) const + { + bool result=false; + float maxDist = (pPos2 - pPos1).magnitude(); + // prevent NaN values which can cause BIH intersection to enter infinite loop + if (maxDist < 1e-10f) + { + pResultHitPos = pPos2; + return false; + } + Vector3 dir = (pPos2 - pPos1)/maxDist; // direction with length of 1 + G3D::Ray ray(pPos1, dir); + float dist = getIntersectionTime(ray, maxDist, false); + if (dist < maxDist) + { + pResultHitPos = pPos1 + dir * dist; + if (pModifyDist < 0) + { + if ((pResultHitPos - pPos1).magnitude() > -pModifyDist) + { + pResultHitPos = pResultHitPos + dir*pModifyDist; + } + else + { + pResultHitPos = pPos1; + } + } + else + { + pResultHitPos = pResultHitPos + dir*pModifyDist; + } + result = true; + } + else + { + pResultHitPos = pPos2; + result = false; + } + return result; + } + + //========================================================= + + float StaticMapTree::getHeight(const Vector3& pPos) const + { + float height = G3D::inf(); + Vector3 dir = Vector3(0,0,-1); + G3D::Ray ray(pPos, dir); // direction with length of 1 + float maxDist = VMapDefinitions::getMaxCanFallDistance(); + float dist = getIntersectionTime(ray, maxDist, false); + if (dist < maxDist) + { + height = pPos.z - dist; + } + return(height); + } + + //========================================================= + + bool StaticMapTree::CanLoadMap(const std::string &vmapPath, uint32 mapID, uint32 tileX, uint32 tileY) + { + std::string basePath = vmapPath; + if (basePath.length() > 0 && (basePath[basePath.length()-1] != '/' || basePath[basePath.length()-1] != '\\')) + basePath.append("/"); + std::string fullname = basePath + VMapManager2::getMapFileName(mapID); + bool success = true; + FILE *rf = fopen(fullname.c_str(), "rb"); + if (!rf) + return false; + // TODO: check magic number when implemented... + char tiled; + char chunk[8]; + if (!readChunk(rf, chunk, VMAP_MAGIC, 8) || fread(&tiled, sizeof(char), 1, rf) != 1) + { + fclose(rf); + return false; + } + if (tiled) + { + std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY); + FILE* tf = fopen(tilefile.c_str(), "rb"); + if (!tf) + success = false; + else + fclose(tf); + } + fclose(rf); + return success; + } + + //========================================================= + + bool StaticMapTree::InitMap(const std::string &fname, VMapManager2 *vm) + { + std::cout << "Initializing StaticMapTree '" << fname << "'\n"; + bool success = true; + std::string fullname = iBasePath + fname; + FILE *rf = fopen(fullname.c_str(), "rb"); + if (!rf) + return false; + else + { + char chunk[8]; + //general info + if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) success = false; + char tiled; + if (success && fread(&tiled, sizeof(char), 1, rf) != 1) success = false; + iIsTiled = bool(tiled); + // Nodes + if (success && !readChunk(rf, chunk, "NODE", 4)) success = false; + if (success) success = iTree.readFromFile(rf); + if (success) + { + iNTreeValues = iTree.primCount(); + iTreeValues = new ModelInstance[iNTreeValues]; + } + + if (success && !readChunk(rf, chunk, "GOBJ", 4)) success = false; + // global model spawns + // only non-tiled maps have them, and if so exactly one (so far at least...) + ModelSpawn spawn; +#ifdef VMAP_DEBUG + std::cout << "Map isTiled:" << bool(iIsTiled) << std::endl; +#endif + if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn)) + { + WorldModel *model = vm->acquireModelInstance(iBasePath, spawn.name); + std::cout << "StaticMapTree::InitMap(): loading " << spawn.name << std::endl; + if (model) + { + // assume that global model always is the first and only tree value (could be improved...) + iTreeValues[0] = ModelInstance(spawn, model); + iLoadedSpawns[0] = 1; + } + else + { + success = false; + std::cout << "error: could not acquire WorldModel pointer!\n"; + } + } + + fclose(rf); + } + return success; + } + + //========================================================= + + void StaticMapTree::UnloadMap(VMapManager2 *vm) + { + for (loadedSpawnMap::iterator i = iLoadedSpawns.begin(); i != iLoadedSpawns.end(); ++i) + { + iTreeValues[i->first].setUnloaded(); + for (uint32 refCount = 0; refCount < i->second; ++refCount) + vm->releaseModelInstance(iTreeValues[i->first].name); + } + iLoadedSpawns.clear(); + iLoadedTiles.clear(); + } + + //========================================================= + + bool StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm) + { + if (!iIsTiled) + { + // currently, core creates grids for all maps, whether it has terrain tiles or not + // so we need "fake" tile loads to know when we can unload map geometry + iLoadedTiles[packTileID(tileX, tileY)] = false; + return true; + } + if (!iTreeValues) + { + std::cout << "Tree has not been initialized!\n"; + return false; + } + bool result = true; + + std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY); + FILE* tf = fopen(tilefile.c_str(), "rb"); + if (tf) + { + uint32 numSpawns; + if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1) + result = false; + for (uint32 i=0; i<numSpawns && result; ++i) + { + // read model spawns + ModelSpawn spawn; + result = ModelSpawn::readFromFile(tf, spawn); + if (result) + { + // acquire model instance + WorldModel *model = vm->acquireModelInstance(iBasePath, spawn.name); + if (!model) std::cout << "error: could not acquire WorldModel pointer!\n"; + + // update tree + uint32 referencedVal; + + fread(&referencedVal, sizeof(uint32), 1, tf); + if (!iLoadedSpawns.count(referencedVal)) + { +#ifdef VMAP_DEBUG + if (referencedVal > iNTreeValues) + { + std::cout << "invalid tree element! (" << referencedVal << "/" << iNTreeValues << ")\n"; + continue; + } +#endif + iTreeValues[referencedVal] = ModelInstance(spawn, model); + iLoadedSpawns[referencedVal] = 1; + } + else + { + ++iLoadedSpawns[referencedVal]; +#ifdef VMAP_DEBUG + if (iTreeValues[referencedVal].ID != spawn.ID) std::cout << "error: trying to load wrong spawn in node!\n"; + else if (iTreeValues[referencedVal].name != spawn.name) std::cout << "error: name collision on GUID="<< spawn.ID << "\n"; +#endif + } + } + } + iLoadedTiles[packTileID(tileX, tileY)] = true; + fclose(tf); + } + else + iLoadedTiles[packTileID(tileX, tileY)] = false; + return result; + } + + //========================================================= + + void StaticMapTree::UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm) + { + uint32 tileID = packTileID(tileX, tileY); + loadedTileMap::iterator tile = iLoadedTiles.find(tileID); + if (tile == iLoadedTiles.end()) + { + std::cout << "WARNING: trying to unload non-loaded tile. Map:" << iMapID << " X:" << tileX << " Y:" << tileY << std::endl; + return; + } + if (tile->second) // file associated with tile + { + std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY); + FILE* tf = fopen(tilefile.c_str(), "rb"); + if (tf) + { + bool result=true; + uint32 numSpawns; + if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1) + result = false; + for (uint32 i=0; i<numSpawns && result; ++i) + { + // read model spawns + ModelSpawn spawn; + result = ModelSpawn::readFromFile(tf, spawn); + if (result) + { + // release model instance + vm->releaseModelInstance(spawn.name); + + // update tree + uint32 referencedNode; + + fread(&referencedNode, sizeof(uint32), 1, tf); + if (!iLoadedSpawns.count(referencedNode)) + { + std::cout << "error! trying to unload non-referenced model '" << spawn.name << "' (ID:" << spawn.ID << ")\n"; + } + else if (--iLoadedSpawns[referencedNode] == 0) + { + //std::cout << "MapTree: removing '" << spawn.name << "' from tree\n"; + iTreeValues[referencedNode].setUnloaded(); + iLoadedSpawns.erase(referencedNode); + } + } + } + fclose(tf); + } + } + iLoadedTiles.erase(tile); + } + +} diff --git a/src/server/shared/vmap/MapTree.h b/src/server/shared/vmap/MapTree.h new file mode 100644 index 00000000000..7955cb92d68 --- /dev/null +++ b/src/server/shared/vmap/MapTree.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MAPTREE_H +#define _MAPTREE_H + +#include "Platform/Define.h" +#include "Utilities/UnorderedMap.h" +#include "BIH.h" + +namespace VMAP +{ + class ModelInstance; + class GroupModel; + class VMapManager2; + + struct LocationInfo + { + LocationInfo(): hitInstance(0), hitModel(0), ground_Z(-G3D::inf()) {}; + const ModelInstance *hitInstance; + const GroupModel *hitModel; + float ground_Z; + }; + + class StaticMapTree + { + typedef UNORDERED_MAP<uint32, bool> loadedTileMap; + typedef UNORDERED_MAP<uint32, uint32> loadedSpawnMap; + private: + uint32 iMapID; + bool iIsTiled; + BIH iTree; + ModelInstance *iTreeValues; // the tree entries + uint32 iNTreeValues; + + // Store all the map tile idents that are loaded for that map + // some maps are not splitted into tiles and we have to make sure, not removing the map before all tiles are removed + // empty tiles have no tile file, hence map with bool instead of just a set (consistency check) + loadedTileMap iLoadedTiles; + // stores <tree_index, reference_count> to invalidate tree values, unload map, and to be able to report errors + loadedSpawnMap iLoadedSpawns; + std::string iBasePath; + + private: + float getIntersectionTime(const G3D::Ray& pRay, float pMaxDist, bool pStopAtFirstHit) const; + //bool containsLoadedMapTile(unsigned int pTileIdent) const { return(iLoadedMapTiles.containsKey(pTileIdent)); } + public: + static std::string getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY); + static uint32 packTileID(uint32 tileX, uint32 tileY) { return tileX<<16 | tileY; } + static void unpackTileID(uint32 ID, uint32 &tileX, uint32 &tileY) { tileX = ID>>16; tileY = ID&0xFF; } + static bool CanLoadMap(const std::string &basePath, uint32 mapID, uint32 tileX, uint32 tileY); + + StaticMapTree(uint32 mapID, const std::string &basePath); + ~StaticMapTree(); + + bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2) const; + bool getObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const; + float getHeight(const G3D::Vector3& pPos) const; + bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const; + bool GetLocationInfo(const Vector3 &pos, LocationInfo &info) const; + + bool InitMap(const std::string &fname, VMapManager2 *vm); + void UnloadMap(VMapManager2 *vm); + bool LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm); + void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2 *vm); + bool isTiled() const { return iIsTiled; } + uint32 numLoadedTiles() const { return iLoadedTiles.size(); } + }; + + struct AreaInfo + { + AreaInfo(): result(false), ground_Z(-G3D::inf()) {}; + bool result; + float ground_Z; + uint32 flags; + int32 adtId; + int32 rootId; + int32 groupId; + }; +} // VMAP + +#endif // _MAPTREE_H diff --git a/src/server/shared/vmap/ModelInstance.cpp b/src/server/shared/vmap/ModelInstance.cpp new file mode 100644 index 00000000000..677a08e147a --- /dev/null +++ b/src/server/shared/vmap/ModelInstance.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ModelInstance.h" +#include "WorldModel.h" +#include "MapTree.h" + +using G3D::Vector3; +using G3D::Ray; + +namespace VMAP +{ + ModelInstance::ModelInstance(const ModelSpawn &spawn, WorldModel *model): ModelSpawn(spawn), iModel(model) + { + iInvRot = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iRot.y/180.f, G3D::pi()*iRot.x/180.f, G3D::pi()*iRot.z/180.f).inverse(); + iInvScale = 1.f/iScale; + } + + bool ModelInstance::intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const + { + if (!iModel) + { + //std::cout << "<object not loaded>\n"; + return false; + } + float time = pRay.intersectionTime(iBound); + if (time == G3D::inf()) + { +// std::cout << "Ray does not hit '" << name << "'\n"; + + return false; + } +// std::cout << "Ray crosses bound of '" << name << "'\n"; +/* std::cout << "ray from:" << pRay.origin().x << ", " << pRay.origin().y << ", " << pRay.origin().z + << " dir:" << pRay.direction().x << ", " << pRay.direction().y << ", " << pRay.direction().z + << " t/tmax:" << time << "/" << pMaxDist; + std::cout << "\nBound lo:" << iBound.low().x << ", " << iBound.low().y << ", " << iBound.low().z << " hi: " + << iBound.high().x << ", " << iBound.high().y << ", " << iBound.high().z << std::endl; */ + // child bounds are defined in object space: + Vector3 p = iInvRot * (pRay.origin() - iPos) * iInvScale; + Ray modRay(p, iInvRot * pRay.direction()); + float distance = pMaxDist * iInvScale; + bool hit = iModel->IntersectRay(modRay, distance, pStopAtFirstHit); + distance *= iScale; + pMaxDist = distance; + return hit; + } + + void ModelInstance::intersectPoint(const G3D::Vector3& p, AreaInfo &info) const + { + if (!iModel) + { +#ifdef VMAP_DEBUG + std::cout << "<object not loaded>\n"; +#endif + return; + } + + // M2 files don't contain area info, only WMO files + if (flags & MOD_M2) + return; + if (!iBound.contains(p)) + return; + // child bounds are defined in object space: + Vector3 pModel = iInvRot * (p - iPos) * iInvScale; + Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); + float zDist; + if (iModel->IntersectPoint(pModel, zDirModel, zDist, info)) + { + Vector3 modelGround = pModel + zDist * zDirModel; + // Transform back to world space. Note that: + // Mat * vec == vec * Mat.transpose() + // and for rotation matrices: Mat.inverse() == Mat.transpose() + float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; + if (info.ground_Z < world_Z) + { + info.ground_Z = world_Z; + info.adtId = adtId; + } + } + } + + bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const + { + if (!iModel) + { +#ifdef VMAP_DEBUG + std::cout << "<object not loaded>\n"; +#endif + return false; + } + + // M2 files don't contain area info, only WMO files + if (flags & MOD_M2) + return false; + if (!iBound.contains(p)) + return false; + // child bounds are defined in object space: + Vector3 pModel = iInvRot * (p - iPos) * iInvScale; + Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); + float zDist; + if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info)) + { + Vector3 modelGround = pModel + zDist * zDirModel; + // Transform back to world space. Note that: + // Mat * vec == vec * Mat.transpose() + // and for rotation matrices: Mat.inverse() == Mat.transpose() + float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; + if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection? + { + info.ground_Z = world_Z; + info.hitInstance = this; + return true; + } + } + return false; + } + + bool ModelInstance::GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const + { + // child bounds are defined in object space: + Vector3 pModel = iInvRot * (p - iPos) * iInvScale; + //Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); + float zDist; + if (info.hitModel->GetLiquidLevel(pModel, zDist)) + { + // calculate world height (zDist in model coords): + // assume WMO not tilted (wouldn't make much sense anyway) + liqHeight = zDist * iScale + iPos.z; + return true; + } + return false; + } + + bool ModelSpawn::readFromFile(FILE *rf, ModelSpawn &spawn) + { + uint32 check=0, nameLen; + check += fread(&spawn.flags, sizeof(uint32), 1, rf); + // EoF? + if (!check) + { + if (ferror(rf)) + std::cout << "Error reading ModelSpawn!\n"; + return false; + } + check += fread(&spawn.adtId, sizeof(uint16), 1, rf); + check += fread(&spawn.ID, sizeof(uint32), 1, rf); + check += fread(&spawn.iPos, sizeof(float), 3, rf); + check += fread(&spawn.iRot, sizeof(float), 3, rf); + check += fread(&spawn.iScale, sizeof(float), 1, rf); + bool has_bound = (spawn.flags & MOD_HAS_BOUND); + if (has_bound) // only WMOs have bound in MPQ, only available after computation + { + Vector3 bLow, bHigh; + check += fread(&bLow, sizeof(float), 3, rf); + check += fread(&bHigh, sizeof(float), 3, rf); + spawn.iBound = G3D::AABox(bLow, bHigh); + } + check += fread(&nameLen, sizeof(uint32), 1, rf); + if(check != (has_bound ? 17 : 11)) + { + std::cout << "Error reading ModelSpawn!\n"; + return false; + } + char nameBuff[500]; + if (nameLen>500) // file names should never be that long, must be file error + { + std::cout << "Error reading ModelSpawn, file name too long!\n"; + return false; + } + check = fread(nameBuff, sizeof(char), nameLen, rf); + if (check != nameLen) + { + std::cout << "Error reading ModelSpawn!\n"; + return false; + } + spawn.name = std::string(nameBuff, nameLen); + return true; + } + + bool ModelSpawn::writeToFile(FILE *wf, const ModelSpawn &spawn) + { + uint32 check=0; + check += fwrite(&spawn.flags, sizeof(uint32), 1, wf); + check += fwrite(&spawn.adtId, sizeof(uint16), 1, wf); + check += fwrite(&spawn.ID, sizeof(uint32), 1, wf); + check += fwrite(&spawn.iPos, sizeof(float), 3, wf); + check += fwrite(&spawn.iRot, sizeof(float), 3, wf); + check += fwrite(&spawn.iScale, sizeof(float), 1, wf); + bool has_bound = (spawn.flags & MOD_HAS_BOUND); + if(has_bound) // only WMOs have bound in MPQ, only available after computation + { + check += fwrite(&spawn.iBound.low(), sizeof(float), 3, wf); + check += fwrite(&spawn.iBound.high(), sizeof(float), 3, wf); + } + uint32 nameLen = spawn.name.length(); + check += fwrite(&nameLen, sizeof(uint32), 1, wf); + if(check != (has_bound ? 17 : 11)) return false; + check = fwrite(spawn.name.c_str(), sizeof(char), nameLen, wf); + if(check != nameLen) return false; + return true; + } + +} diff --git a/src/server/shared/vmap/ModelInstance.h b/src/server/shared/vmap/ModelInstance.h new file mode 100644 index 00000000000..97b3ab632a1 --- /dev/null +++ b/src/server/shared/vmap/ModelInstance.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MODELINSTANCE_H_ +#define _MODELINSTANCE_H_ + +#include <G3D/Matrix3.h> +#include <G3D/Vector3.h> +#include <G3D/AABox.h> +#include <G3D/Ray.h> + +#include "Platform/Define.h" + +namespace VMAP +{ + class WorldModel; + struct AreaInfo; + struct LocationInfo; + + enum ModelFlags + { + MOD_M2 = 1, + MOD_WORLDSPAWN = 1<<1, + MOD_HAS_BOUND = 1<<2 + }; + + class ModelSpawn + { + public: + //mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name + uint32 flags; + uint16 adtId; + uint32 ID; + G3D::Vector3 iPos; + G3D::Vector3 iRot; + float iScale; + G3D::AABox iBound; + std::string name; + bool operator==(const ModelSpawn &other) const { return ID == other.ID; } + //uint32 hashCode() const { return ID; } + // temp? + const G3D::AABox& getBounds() const { return iBound; } + + + static bool readFromFile(FILE *rf, ModelSpawn &spawn); + static bool writeToFile(FILE *rw, const ModelSpawn &spawn); + }; + + class ModelInstance: public ModelSpawn + { + public: + ModelInstance(): iModel(0) {} + ModelInstance(const ModelSpawn &spawn, WorldModel *model); + void setUnloaded() { iModel = 0; } + bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const; + void intersectPoint(const G3D::Vector3& p, AreaInfo &info) const; + bool GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const; + bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const; + protected: + G3D::Matrix3 iInvRot; + float iInvScale; + WorldModel *iModel; + }; +} // namespace VMAP + +#endif // _MODELINSTANCE diff --git a/src/server/shared/vmap/TileAssembler.cpp b/src/server/shared/vmap/TileAssembler.cpp new file mode 100644 index 00000000000..d01b54a7564 --- /dev/null +++ b/src/server/shared/vmap/TileAssembler.cpp @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "WorldModel.h" +#include "TileAssembler.h" +#include "MapTree.h" +#include "BIH.h" +#include "VMapDefinitions.h" + +#include <set> +#include <iomanip> +#include <sstream> +#include <iomanip> + +using G3D::Vector3; +using G3D::AABox; +using G3D::inf; +using std::pair; + +template<> struct BoundsTrait<VMAP::ModelSpawn*> +{ + static void getBounds(const VMAP::ModelSpawn* const &obj, G3D::AABox& out) { out = obj->getBounds(); } +}; + +namespace VMAP +{ + bool readChunk(FILE *rf, char *dest, const char *compare, uint32 len) + { + if (fread(dest, sizeof(char), len, rf) != len) return false; + return memcmp(dest, compare, len) == 0; + } + + Vector3 ModelPosition::transform(const Vector3& pIn) const + { + Vector3 out = pIn * iScale; + out = iRotation * out; + return(out); + } + + //================================================================= + + TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName) + { + iCurrentUniqueNameId = 0; + iFilterMethod = NULL; + iSrcDir = pSrcDirName; + iDestDir = pDestDirName; + //mkdir(iDestDir); + //init(); + } + + TileAssembler::~TileAssembler() + { + //delete iCoordModelMapping; + } + + bool TileAssembler::convertWorld2() + { + std::set<std::string> spawnedModelFiles; + bool success = readMapSpawns(); + if (!success) + return false; + + // export Map data + for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end() && success; ++map_iter) + { + // build global map tree + std::vector<ModelSpawn*> mapSpawns; + UniqueEntryMap::iterator entry; + for (entry = map_iter->second->UniqueEntries.begin(); entry != map_iter->second->UniqueEntries.end(); ++entry) + { + // M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail + if (entry->second.flags & MOD_M2) + { + if (!calculateTransformedBound(entry->second)) + break; + } + else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/ + { + // TODO: remove extractor hack and uncomment below line: + //entry->second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f); + entry->second.iBound = entry->second.iBound + Vector3(533.33333f*32, 533.33333f*32, 0.f); + } + mapSpawns.push_back(&(entry->second)); + spawnedModelFiles.insert(entry->second.name); + } + + BIH pTree; + pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>::getBounds); + + // ===> possibly move this code to StaticMapTree class + std::map<uint32, uint32> modelNodeIdx; + for (uint32 i=0; i<mapSpawns.size(); ++i) + modelNodeIdx.insert(pair<uint32, uint32>(mapSpawns[i]->ID, i)); + if (!modelNodeIdx.empty()) + printf("min GUID: %u, max GUID: %u\n", modelNodeIdx.begin()->first, modelNodeIdx.rbegin()->first); + + // write map tree file + std::stringstream mapfilename; + mapfilename << iDestDir << "/" << std::setfill('0') << std::setw(3) << map_iter->first << ".vmtree"; + FILE *mapfile = fopen(mapfilename.str().c_str(), "wb"); + if (!mapfile) + { + success = false; + printf("Cannot open %s\n", mapfilename.str().c_str()); + break; + } + + //general info + if (success && fwrite(VMAP_MAGIC, 1, 8, mapfile) != 8) success = false; + uint32 globalTileID = StaticMapTree::packTileID(65, 65); + pair<TileMap::iterator, TileMap::iterator> globalRange = map_iter->second->TileEntries.equal_range(globalTileID); + char isTiled = globalRange.first == globalRange.second; // only maps without terrain (tiles) have global WMO + if (success && fwrite(&isTiled, sizeof(char), 1, mapfile) != 1) success = false; + // Nodes + if (success && fwrite("NODE", 4, 1, mapfile) != 1) success = false; + if (success) success = pTree.writeToFile(mapfile); + // global map spawns (WDT), if any (most instances) + if (success && fwrite("GOBJ", 4, 1, mapfile) != 1) success = false; + + for (TileMap::iterator glob=globalRange.first; glob != globalRange.second && success; ++glob) + { + success = ModelSpawn::writeToFile(mapfile, map_iter->second->UniqueEntries[glob->second]); + } + + fclose(mapfile); + + // <==== + + // write map tile files, similar to ADT files, only with extra BSP tree node info + TileMap &tileEntries = map_iter->second->TileEntries; + TileMap::iterator tile; + for (tile = tileEntries.begin(); tile != tileEntries.end(); ++tile) + { + const ModelSpawn &spawn = map_iter->second->UniqueEntries[tile->second]; + if (spawn.flags & MOD_WORLDSPAWN) // WDT spawn, saved as tile 65/65 currently... + continue; + uint32 nSpawns = tileEntries.count(tile->first); + std::stringstream tilefilename; + tilefilename.fill('0'); + tilefilename << iDestDir << "/" << std::setw(3) << map_iter->first << "_"; + uint32 x, y; + StaticMapTree::unpackTileID(tile->first, x, y); + tilefilename << std::setw(2) << x << "_" << std::setw(2) << y << ".vmtile"; + FILE *tilefile = fopen(tilefilename.str().c_str(), "wb"); + // write number of tile spawns + if (success && fwrite(&nSpawns, sizeof(uint32), 1, tilefile) != 1) success = false; + // write tile spawns + for (uint32 s=0; s<nSpawns; ++s) + { + if (s) + ++tile; + const ModelSpawn &spawn2 = map_iter->second->UniqueEntries[tile->second]; + success = success && ModelSpawn::writeToFile(tilefile, spawn2); + // MapTree nodes to update when loading tile: + std::map<uint32, uint32>::iterator nIdx = modelNodeIdx.find(spawn2.ID); + if (success && fwrite(&nIdx->second, sizeof(uint32), 1, tilefile) != 1) success = false; + } + fclose(tilefile); + } + // break; //test, extract only first map; TODO: remvoe this line + } + + // export objects + std::cout << "\nConverting Model Files" << std::endl; + for (std::set<std::string>::iterator mfile = spawnedModelFiles.begin(); mfile != spawnedModelFiles.end(); ++mfile) + { + std::cout << "Converting " << *mfile << std::endl; + if (!convertRawFile(*mfile)) + { + std::cout << "error converting " << *mfile << std::endl; + success = false; + break; + } + } + + //cleanup: + for (MapData::iterator map_iter = mapData.begin(); map_iter != mapData.end(); ++map_iter) + { + delete map_iter->second; + } + return success; + } + + bool TileAssembler::readMapSpawns() + { + std::string fname = iSrcDir + "/dir_bin"; + FILE *dirf = fopen(fname.c_str(), "rb"); + if (!dirf) + { + printf("Could not read dir_bin file!\n"); + return false; + } + printf("Read coordinate mapping...\n"); + uint32 mapID, tileX, tileY, check=0; + G3D::Vector3 v1, v2; + ModelSpawn spawn; + while (!feof(dirf)) + { + check = 0; + // read mapID, tileX, tileY, Flags, adtID, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name + check += fread(&mapID, sizeof(uint32), 1, dirf); + if (check == 0) // EoF... + break; + check += fread(&tileX, sizeof(uint32), 1, dirf); + check += fread(&tileY, sizeof(uint32), 1, dirf); + if (!ModelSpawn::readFromFile(dirf, spawn)) + break; + + MapSpawns *current; + MapData::iterator map_iter = mapData.find(mapID); + if (map_iter == mapData.end()) + { + printf("spawning Map %d\n", mapID); + mapData[mapID] = current = new MapSpawns(); + } + else current = (*map_iter).second; + current->UniqueEntries.insert(pair<uint32, ModelSpawn>(spawn.ID, spawn)); + current->TileEntries.insert(pair<uint32, uint32>(StaticMapTree::packTileID(tileX, tileY), spawn.ID)); + } + bool success = (ferror(dirf) == 0); + fclose(dirf); + return success; + } + + bool TileAssembler::calculateTransformedBound(ModelSpawn &spawn) + { + std::string modelFilename = iSrcDir + "/" + spawn.name; + ModelPosition modelPosition; + modelPosition.iDir = spawn.iRot; + modelPosition.iScale = spawn.iScale; + modelPosition.init(); + + FILE *rf = fopen(modelFilename.c_str(), "rb"); + if (!rf) + { + printf("ERROR: Can't open model file: %s\n", modelFilename.c_str()); + return false; + } + + AABox modelBound; + bool boundEmpty=true; + char ident[8]; + + int readOperation = 1; + + // temporary use defines to simplify read/check code (close file and return at fail) + #define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \ + fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }readOperation++; + #define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \ + fclose(rf); printf("cmpfail, %s!=%s\n", V, S);return(false); } + + READ_OR_RETURN(&ident, 8); + CMP_OR_RETURN(ident, "VMAP003"); + + // we have to read one int. This is needed during the export and we have to skip it here + uint32 tempNVectors; + READ_OR_RETURN(&tempNVectors, sizeof(tempNVectors)); + + uint32 groups, wmoRootId; + char blockId[5]; + blockId[4] = 0; + int blocksize; + float *vectorarray = 0; + + READ_OR_RETURN(&groups, sizeof(uint32)); + READ_OR_RETURN(&wmoRootId, sizeof(uint32)); + if (groups != 1) printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str()); + + for (uint32 g=0; g<groups; ++g) // should be only one for M2 files... + { + fseek(rf, 3*sizeof(uint32) + 6*sizeof(float), SEEK_CUR); + + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "GRP "); + READ_OR_RETURN(&blocksize, sizeof(int)); + fseek(rf, blocksize, SEEK_CUR); + + // ---- indexes + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "INDX"); + READ_OR_RETURN(&blocksize, sizeof(int)); + fseek(rf, blocksize, SEEK_CUR); + + // ---- vectors + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "VERT"); + READ_OR_RETURN(&blocksize, sizeof(int)); + uint32 nvectors; + READ_OR_RETURN(&nvectors, sizeof(uint32)); + + if (nvectors >0) + { + vectorarray = new float[nvectors*3]; + READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3); + } + else + { + std::cout << "error: model '" << spawn.name << "' has no geometry!" << std::endl; + return false; + } + + for (uint32 i=0, indexNo=0; indexNo<nvectors; indexNo++, i+=3) + { + Vector3 v = Vector3(vectorarray[i+0], vectorarray[i+1], vectorarray[i+2]); + v = modelPosition.transform(v); + + if (boundEmpty) + modelBound = AABox(v, v), boundEmpty=false; + else + modelBound.merge(v); + } + delete[] vectorarray; + // drop of temporary use defines + #undef READ_OR_RETURN + #undef CMP_OR_RETURN + } + spawn.iBound = modelBound + spawn.iPos; + spawn.flags |= MOD_HAS_BOUND; + fclose(rf); + return true; + } + + struct WMOLiquidHeader + { + int xverts, yverts, xtiles, ytiles; + float pos_x; + float pos_y; + float pos_z; + short type; + }; + //================================================================= + bool TileAssembler::convertRawFile(const std::string& pModelFilename) + { + bool success = true; + std::string filename = iSrcDir; + if (filename.length() >0) + filename.append("/"); + filename.append(pModelFilename); + FILE *rf = fopen(filename.c_str(), "rb"); + + if (!rf) + { + printf("ERROR: Can't open model file in form: %s",pModelFilename.c_str()); + printf("... or form: %s",filename.c_str() ); + return false; + } + + char ident[8]; + + int readOperation = 1; + + // temporary use defines to simplify read/check code (close file and return at fail) + #define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \ + fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }readOperation++; + #define CMP_OR_RETURN(V,S) if(strcmp((V),(S)) != 0) { \ + fclose(rf); printf("cmpfail, %s!=%s\n", V, S);return(false); } + + READ_OR_RETURN(&ident, 8); + CMP_OR_RETURN(ident, "VMAP003"); + + // we have to read one int. This is needed during the export and we have to skip it here + uint32 tempNVectors; + READ_OR_RETURN(&tempNVectors, sizeof(tempNVectors)); + + uint32 groups; + uint32 RootWMOID; + char blockId[5]; + blockId[4] = 0; + int blocksize; + + READ_OR_RETURN(&groups, sizeof(uint32)); + READ_OR_RETURN(&RootWMOID, sizeof(uint32)); + + std::vector<GroupModel> groupsArray; + + for (uint32 g=0; g<groups; ++g) + { + std::vector<MeshTriangle> triangles; + std::vector<Vector3> vertexArray; + + uint32 mogpflags, GroupWMOID; + READ_OR_RETURN(&mogpflags, sizeof(uint32)); + READ_OR_RETURN(&GroupWMOID, sizeof(uint32)); + + float bbox1[3], bbox2[3]; + READ_OR_RETURN(bbox1, sizeof(float)*3); + READ_OR_RETURN(bbox2, sizeof(float)*3); + + uint32 liquidflags; + READ_OR_RETURN(&liquidflags, sizeof(uint32)); + + // will this ever be used? what is it good for anyway?? + uint32 branches; + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "GRP "); + READ_OR_RETURN(&blocksize, sizeof(int)); + READ_OR_RETURN(&branches, sizeof(uint32)); + for (uint32 b=0; b<branches; ++b) + { + uint32 indexes; + // indexes for each branch (not used jet) + READ_OR_RETURN(&indexes, sizeof(uint32)); + } + + // ---- indexes + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "INDX"); + READ_OR_RETURN(&blocksize, sizeof(int)); + uint32 nindexes; + READ_OR_RETURN(&nindexes, sizeof(uint32)); + if (nindexes >0) + { + uint16 *indexarray = new uint16[nindexes]; + READ_OR_RETURN(indexarray, nindexes*sizeof(uint16)); + for (uint32 i=0; i<nindexes; i+=3) + { + triangles.push_back(MeshTriangle(indexarray[i], indexarray[i+1], indexarray[i+2])); + } + delete[] indexarray; + } + + // ---- vectors + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "VERT"); + READ_OR_RETURN(&blocksize, sizeof(int)); + uint32 nvectors; + READ_OR_RETURN(&nvectors, sizeof(uint32)); + + if (nvectors >0) + { + float *vectorarray = new float[nvectors*3]; + READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3); + for (uint32 i=0; i<nvectors; ++i) + { + vertexArray.push_back( Vector3(vectorarray + 3*i) ); + } + delete[] vectorarray; + } + // ----- liquid + WmoLiquid *liquid = 0; + if (liquidflags& 1) + { + WMOLiquidHeader hlq; + READ_OR_RETURN(&blockId, 4); + CMP_OR_RETURN(blockId, "LIQU"); + READ_OR_RETURN(&blocksize, sizeof(int)); + READ_OR_RETURN(&hlq, sizeof(WMOLiquidHeader)); + liquid = new WmoLiquid(hlq.xtiles, hlq.ytiles, Vector3(hlq.pos_x, hlq.pos_y, hlq.pos_z), hlq.type); + uint32 size = hlq.xverts*hlq.yverts; + READ_OR_RETURN(liquid->GetHeightStorage(), size*sizeof(float)); + size = hlq.xtiles*hlq.ytiles; + READ_OR_RETURN(liquid->GetFlagsStorage(), size); + } + + groupsArray.push_back(GroupModel(mogpflags, GroupWMOID, AABox(Vector3(bbox1), Vector3(bbox2)))); + groupsArray.back().setMeshData(vertexArray, triangles); + groupsArray.back().setLiquidData(liquid); + + // drop of temporary use defines + #undef READ_OR_RETURN + #undef CMP_OR_RETURN + + } + fclose(rf); + + // write WorldModel + WorldModel model; + model.setRootWmoID(RootWMOID); + if (groupsArray.size()) + { + model.setGroupModels(groupsArray); + success = model.writeFile(iDestDir + "/" + pModelFilename + ".vmo"); + } + + //std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl; + return success; + } +} diff --git a/src/server/shared/vmap/TileAssembler.h b/src/server/shared/vmap/TileAssembler.h new file mode 100644 index 00000000000..b26735708af --- /dev/null +++ b/src/server/shared/vmap/TileAssembler.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _TILEASSEMBLER_H_ +#define _TILEASSEMBLER_H_ + +#include <G3D/Vector3.h> +#include <G3D/Matrix3.h> +#include <map> + +#include "ModelInstance.h" + +namespace VMAP +{ + /** + This Class is used to convert raw vector data into balanced BSP-Trees. + To start the conversion call convertWorld(). + */ + //=============================================== + + class ModelPosition + { + private: + G3D::Matrix3 iRotation; + public: + G3D::Vector3 iPos; + G3D::Vector3 iDir; + float iScale; + void init() + { + iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iDir.y/180.f, G3D::pi()*iDir.x/180.f, G3D::pi()*iDir.z/180.f); + } + G3D::Vector3 transform(const G3D::Vector3& pIn) const; + void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; } + }; + + typedef std::map<uint32, ModelSpawn> UniqueEntryMap; + typedef std::multimap<uint32, uint32> TileMap; + + struct MapSpawns + { + UniqueEntryMap UniqueEntries; + TileMap TileEntries; + }; + + typedef std::map<uint32, MapSpawns*> MapData; + //=============================================== + + class TileAssembler + { + private: + std::string iDestDir; + std::string iSrcDir; + bool (*iFilterMethod)(char *pName); + G3D::Table<std::string, unsigned int > iUniqueNameIds; + unsigned int iCurrentUniqueNameId; + MapData mapData; + + public: + TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName); + virtual ~TileAssembler(); + + bool convertWorld2(); + bool readMapSpawns(); + bool calculateTransformedBound(ModelSpawn &spawn); + + bool convertRawFile(const std::string& pModelFilename); + void setModelNameFilterMethod(bool (*pFilterMethod)(char *pName)) { iFilterMethod = pFilterMethod; } + std::string getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName); + unsigned int getUniqueNameId(const std::string pName); + }; + +} // VMAP +#endif /*_TILEASSEMBLER_H_*/ diff --git a/src/server/shared/vmap/VMapDefinitions.h b/src/server/shared/vmap/VMapDefinitions.h new file mode 100644 index 00000000000..e4a34cc1397 --- /dev/null +++ b/src/server/shared/vmap/VMapDefinitions.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _VMAPDEFINITIONS_H +#define _VMAPDEFINITIONS_H +#include <cstring> + +#define LIQUID_TILE_SIZE (533.333f / 128.f) + +namespace VMAP +{ + //===================================== + #define MAX_CAN_FALL_DISTANCE 10.0f + const char VMAP_MAGIC[] = "VMAP_3.0"; + + class VMapDefinitions + { + public: + static float getMaxCanFallDistance() { return MAX_CAN_FALL_DISTANCE; } + }; + + //====================================== + + // defined in TileAssembler.cpp currently... + bool readChunk(FILE *rf, char *dest, const char *compare, uint32 len); +} +#endif diff --git a/src/server/shared/vmap/VMapFactory.cpp b/src/server/shared/vmap/VMapFactory.cpp new file mode 100644 index 00000000000..331acbace47 --- /dev/null +++ b/src/server/shared/vmap/VMapFactory.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sys/types.h> +#include "VMapFactory.h" +#include "VMapManager2.h" + +using namespace G3D; + +namespace VMAP +{ + void chompAndTrim(std::string& str) + { + while(str.length() >0) + { + char lc = str[str.length()-1]; + if(lc == '\r' || lc == '\n' || lc == ' ' || lc == '"' || lc == '\'') + { + str = str.substr(0,str.length()-1); + } + else + { + break; + } + } + while(str.length() >0) + { + char lc = str[0]; + if(lc == ' ' || lc == '"' || lc == '\'') + { + str = str.substr(1,str.length()-1); + } + else + { + break; + } + } + } + + IVMapManager *gVMapManager = 0; + Table<unsigned int , bool>* iIgnoreSpellIds=0; + + //=============================================== + // result false, if no more id are found + + bool getNextId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId) + { + bool result = false; + unsigned int i; + for(i=pStartPos;i<pString.size(); ++i) + { + if(pString[i] == ',') + { + break; + } + } + if(i>pStartPos) + { + std::string idString = pString.substr(pStartPos, i-pStartPos); + pStartPos = i+1; + chompAndTrim(idString); + pId = atoi(idString.c_str()); + result = true; + } + return(result); + } + + //=============================================== + /** + parameter: String of map ids. Delimiter = "," + */ + + void VMapFactory::preventSpellsFromBeingTestedForLoS(const char* pSpellIdString) + { + if(!iIgnoreSpellIds) + iIgnoreSpellIds = new Table<unsigned int , bool>(); + if(pSpellIdString != NULL) + { + unsigned int pos =0; + unsigned int id; + std::string confString(pSpellIdString); + chompAndTrim(confString); + while(getNextId(confString, pos, id)) + { + iIgnoreSpellIds->set(id, true); + } + } + } + + //=============================================== + + bool VMapFactory::checkSpellForLoS(unsigned int pSpellId) + { + return(!iIgnoreSpellIds->containsKey(pSpellId)); + } + + //=============================================== + // just return the instance + IVMapManager* VMapFactory::createOrGetVMapManager() + { + if(gVMapManager == 0) + gVMapManager= new VMapManager2(); // should be taken from config ... Please change if you like :-) + return gVMapManager; + } + + //=============================================== + // delete all internal data structures + void VMapFactory::clear() + { + if(iIgnoreSpellIds) + { + delete iIgnoreSpellIds; + iIgnoreSpellIds = NULL; + } + if(gVMapManager) + { + delete gVMapManager; + gVMapManager = NULL; + } + } +} diff --git a/src/server/shared/vmap/VMapFactory.h b/src/server/shared/vmap/VMapFactory.h new file mode 100644 index 00000000000..8dc2c01938a --- /dev/null +++ b/src/server/shared/vmap/VMapFactory.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _VMAPFACTORY_H +#define _VMAPFACTORY_H + +#include "IVMapManager.h" + +/** +This is the access point to the VMapManager. +*/ + +namespace VMAP +{ + //=========================================================== + + class VMapFactory + { + public: + static IVMapManager* createOrGetVMapManager(); + static void clear(); + + static void preventSpellsFromBeingTestedForLoS(const char* pSpellIdString); + static bool checkSpellForLoS(unsigned int pSpellId); + }; + +} +#endif diff --git a/src/server/shared/vmap/VMapManager2.cpp b/src/server/shared/vmap/VMapManager2.cpp new file mode 100644 index 00000000000..1e8a84aee52 --- /dev/null +++ b/src/server/shared/vmap/VMapManager2.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <iostream> +#include <iomanip> +#include <string> +#include <sstream> +#include "VMapManager2.h" +#include "MapTree.h" +#include "ModelInstance.h" +#include "WorldModel.h" +#include "VMapDefinitions.h" + +using G3D::Vector3; + +namespace VMAP +{ + + //========================================================= + + VMapManager2::VMapManager2() + { + } + + //========================================================= + + VMapManager2::~VMapManager2(void) + { + for (InstanceTreeMap::iterator i = iInstanceMapTrees.begin(); i != iInstanceMapTrees.end(); ++i) + { + delete i->second; + } + for (ModelFileMap::iterator i = iLoadedModelFiles.begin(); i != iLoadedModelFiles.end(); ++i) + { + delete i->second.getModel(); + } + } + + //========================================================= + + Vector3 VMapManager2::convertPositionToInternalRep(float x, float y, float z) const + { + Vector3 pos; + const float mid = 0.5 * 64.0 * 533.33333333f; + pos.x = mid - x; + pos.y = mid - y; + pos.z = z; + + return pos; + } + + //========================================================= + + Vector3 VMapManager2::convertPositionToMangosRep(float x, float y, float z) const + { + Vector3 pos; + const float mid = 0.5 * 64.0 * 533.33333333f; + pos.x = mid - x; + pos.y = mid - y; + pos.z = z; + + return pos; + } + //========================================================= + + // move to MapTree too? + std::string VMapManager2::getMapFileName(unsigned int pMapId) + { + std::stringstream fname; + fname.width(3); + fname << std::setfill('0') << pMapId << std::string(MAP_FILENAME_EXTENSION2); + return fname.str(); + } + + //========================================================= + /** + Block maps from being used. + parameter: String of map ids. Delimiter = "," + e.g.: "0,1,590" + */ + + void VMapManager2::preventMapsFromBeingUsed(const char* pMapIdString) + { + iIgnoreMapIds.clear(); + if (pMapIdString != NULL) + { + std::string map_str; + std::stringstream map_ss; + map_ss.str(std::string(pMapIdString)); + while (std::getline(map_ss, map_str, ',')) + { + std::stringstream ss2(map_str); + int map_num = -1; + ss2 >> map_num; + if (map_num >= 0) + { + std::cout << "ingoring Map " << map_num << " for VMaps\n"; + iIgnoreMapIds[map_num] = true; + // unload map in case it is loaded + unloadMap(map_num); + } + } + } + } + + //========================================================= + + int VMapManager2::loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) + { + int result = VMAP_LOAD_RESULT_IGNORED; + if (isMapLoadingEnabled() && !iIgnoreMapIds.count(pMapId)) + { + if (_loadMap(pMapId, pBasePath, x, y)) + result = VMAP_LOAD_RESULT_OK; + else + result = VMAP_LOAD_RESULT_ERROR; + } + return result; + } + + //========================================================= + // load one tile (internal use only) + + bool VMapManager2::_loadMap(unsigned int pMapId, const std::string &basePath, uint32 tileX, uint32 tileY) + { + InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree == iInstanceMapTrees.end()) + { + std::string mapFileName = getMapFileName(pMapId); + StaticMapTree *newTree = new StaticMapTree(pMapId, basePath); + if (!newTree->InitMap(mapFileName, this)) + return false; + instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(pMapId, newTree)).first; + } + return instanceTree->second->LoadMapTile(tileX, tileY, this); + } + + //========================================================= + + void VMapManager2::unloadMap(unsigned int pMapId) + { + InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree != iInstanceMapTrees.end()) + { + instanceTree->second->UnloadMap(this); + if (instanceTree->second->numLoadedTiles() == 0) + { + delete instanceTree->second; + iInstanceMapTrees.erase(pMapId); + } + } + } + + //========================================================= + + void VMapManager2::unloadMap(unsigned int pMapId, int x, int y) + { + InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree != iInstanceMapTrees.end()) + { + instanceTree->second->UnloadMapTile(x, y, this); + if (instanceTree->second->numLoadedTiles() == 0) + { + delete instanceTree->second; + iInstanceMapTrees.erase(pMapId); + } + } + } + + //========================================================== + + bool VMapManager2::isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) + { + if (!isLineOfSightCalcEnabled()) return true; + bool result = true; + InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree != iInstanceMapTrees.end()) + { + Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1); + Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2); + if (pos1 != pos2) + { + result = instanceTree->second->isInLineOfSight(pos1, pos2); + } + } + return result; + } + //========================================================= + /** + get the hit position and return true if we hit something + otherwise the result pos will be the dest pos + */ + bool VMapManager2::getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist) + { + bool result = false; + rx=x2; + ry=y2; + rz=z2; + if (isLineOfSightCalcEnabled()) + { + InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree != iInstanceMapTrees.end()) + { + Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1); + Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2); + Vector3 resultPos; + result = instanceTree->second->getObjectHitPos(pos1, pos2, resultPos, pModifyDist); + resultPos = convertPositionToMangosRep(resultPos.x,resultPos.y,resultPos.z); + rx = resultPos.x; + ry = resultPos.y; + rz = resultPos.z; + } + } + return result; + } + + //========================================================= + /** + get height or INVALID_HEIGHT if no height available + */ + + float VMapManager2::getHeight(unsigned int pMapId, float x, float y, float z) + { + float height = VMAP_INVALID_HEIGHT_VALUE; //no height + if (isHeightCalcEnabled()) + { + InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree != iInstanceMapTrees.end()) + { + Vector3 pos = convertPositionToInternalRep(x,y,z); + height = instanceTree->second->getHeight(pos); + if (!(height < G3D::inf())) + { + height = VMAP_INVALID_HEIGHT_VALUE; //no height + } + } + } + return height; + } + + //========================================================= + + bool VMapManager2::getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const + { + bool result=false; + InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree != iInstanceMapTrees.end()) + { + Vector3 pos = convertPositionToInternalRep(x, y, z); + result = instanceTree->second->getAreaInfo(pos, flags, adtId, rootId, groupId); + // z is not touched by convertPositionToMangosRep(), so just copy + z = pos.z; + } + return(result); + } + + bool VMapManager2::GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const + { + InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(pMapId); + if (instanceTree != iInstanceMapTrees.end()) + { + LocationInfo info; + Vector3 pos = convertPositionToInternalRep(x, y, z); + if (instanceTree->second->GetLocationInfo(pos, info)) + { + floor = info.ground_Z; + type = info.hitModel->GetLiquidType(); + if (ReqLiquidType && !(type & ReqLiquidType)) + return false; + if (info.hitInstance->GetLiquidLevel(pos, info, level)) + return true; + } + } + return false; + } + + //========================================================= + + WorldModel* VMapManager2::acquireModelInstance(const std::string &basepath, const std::string &filename) + { + ModelFileMap::iterator model = iLoadedModelFiles.find(filename); + if (model == iLoadedModelFiles.end()) + { + WorldModel *worldmodel = new WorldModel(); + if (!worldmodel->readFile(basepath + filename + ".vmo")) + { + std::cout << "VMapManager2: could not load '" << basepath << filename << ".vmo'!\n"; + delete worldmodel; + return NULL; + } + std::cout << "VMapManager2: loading file '" << basepath << filename << "'.\n"; + model = iLoadedModelFiles.insert(std::pair<std::string, ManagedModel>(filename, ManagedModel())).first; + model->second.setModel(worldmodel); + } + model->second.incRefCount(); + return model->second.getModel(); + } + + void VMapManager2::releaseModelInstance(const std::string &filename) + { + ModelFileMap::iterator model = iLoadedModelFiles.find(filename); + if (model == iLoadedModelFiles.end()) + { + std::cout << "VMapManager2: trying to unload non-loaded file '" << filename << "'!\n"; + return; + } + if( model->second.decRefCount() == 0) + { + std::cout << "VMapManager2: unloading file '" << filename << "'.\n"; + delete model->second.getModel(); + iLoadedModelFiles.erase(model); + } + } + //========================================================= + + bool VMapManager2::existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) + { + return StaticMapTree::CanLoadMap(std::string(pBasePath), pMapId, x, y); + } + +} // namespace VMAP diff --git a/src/server/shared/vmap/VMapManager2.h b/src/server/shared/vmap/VMapManager2.h new file mode 100644 index 00000000000..5f03b87b07f --- /dev/null +++ b/src/server/shared/vmap/VMapManager2.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _VMAPMANAGER2_H +#define _VMAPMANAGER2_H + +#include "IVMapManager.h" +#include "Utilities/UnorderedMap.h" +#include "Platform/Define.h" +#include <G3D/Vector3.h> + +//=========================================================== + +#define MAP_FILENAME_EXTENSION2 ".vmtree" + +#define FILENAMEBUFFER_SIZE 500 + +/** +This is the main Class to manage loading and unloading of maps, line of sight, height calculation and so on. +For each map or map tile to load it reads a directory file that contains the ModelContainer files used by this map or map tile. +Each global map or instance has its own dynamic BSP-Tree. +The loaded ModelContainers are included in one of these BSP-Trees. +Additionally a table to match map ids and map names is used. +*/ + +//=========================================================== + +namespace VMAP +{ + class StaticMapTree; + class WorldModel; + + class ManagedModel + { + public: + ManagedModel(): iModel(0), iRefCount(0) {} + void setModel(WorldModel *model) { iModel = model; } + WorldModel *getModel() { return iModel; } + void incRefCount() { ++iRefCount; } + int decRefCount() { return --iRefCount; } + protected: + WorldModel *iModel; + int iRefCount; + }; + + typedef UNORDERED_MAP<uint32 , StaticMapTree *> InstanceTreeMap; + typedef UNORDERED_MAP<std::string, ManagedModel> ModelFileMap; + + class VMapManager2 : public IVMapManager + { + protected: + // Tree to check collision + ModelFileMap iLoadedModelFiles; + InstanceTreeMap iInstanceMapTrees; + // UNORDERED_MAP<unsigned int , bool> iMapsSplitIntoTiles; + UNORDERED_MAP<unsigned int , bool> iIgnoreMapIds; + + bool _loadMap(uint32 pMapId, const std::string &basePath, uint32 tileX, uint32 tileY); + /* void _unloadMap(uint32 pMapId, uint32 x, uint32 y); */ + + public: + // public for debug + G3D::Vector3 convertPositionToInternalRep(float x, float y, float z) const; + G3D::Vector3 convertPositionToMangosRep(float x, float y, float z) const; + static std::string getMapFileName(unsigned int pMapId); + + VMapManager2(); + ~VMapManager2(void); + + int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y); + + void unloadMap(unsigned int pMapId, int x, int y); + void unloadMap(unsigned int pMapId); + + bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) ; + /** + fill the hit pos and return true, if an object was hit + */ + bool getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist); + float getHeight(unsigned int pMapId, float x, float y, float z); + + bool processCommand(char *pCommand) { return false; } // for debug and extensions + + void preventMapsFromBeingUsed(const char* pMapIdString); + bool getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const; + bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const; + + WorldModel* acquireModelInstance(const std::string &basepath, const std::string &filename); + void releaseModelInstance(const std::string &filename); + + // what's the use of this? o.O + virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const + { + return getMapFileName(pMapId); + } + virtual bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y); + }; +} +#endif diff --git a/src/server/shared/vmap/VMapTools.h b/src/server/shared/vmap/VMapTools.h new file mode 100644 index 00000000000..dbbd9af9271 --- /dev/null +++ b/src/server/shared/vmap/VMapTools.h @@ -0,0 +1,150 @@ +/* +* Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _VMAPTOOLS_H +#define _VMAPTOOLS_H + +#include <G3D/CollisionDetection.h> +#include <G3D/AABox.h> + +#include "NodeValueAccess.h" + +/** +The Class is mainly taken from G3D/AABSPTree.h but modified to be able to use our internal data structure. +This is an iterator that helps us analysing the BSP-Trees. +The collision detection is modified to return true, if we are inside an object. +*/ + +namespace VMAP +{ + template<class TValue> + class IntersectionCallBack { + public: + TValue* closestEntity; + G3D::Vector3 hitLocation; + G3D::Vector3 hitNormal; + + void operator()(const G3D::Ray& ray, const TValue* entity, bool pStopAtFirstHit, float& distance) { + entity->intersect(ray, distance, pStopAtFirstHit, hitLocation, hitNormal); + } + }; + + //============================================================== + //============================================================== + //============================================================== + + class MyCollisionDetection + { + private: + public: + + static bool collisionLocationForMovingPointFixedAABox( + const G3D::Vector3& origin, + const G3D::Vector3& dir, + const G3D::AABox& box, + G3D::Vector3& location, + bool& Inside) + { + + // Integer representation of a floating-point value. +#define IR(x) (reinterpret_cast<G3D::uint32 const&>(x)) + + Inside = true; + const G3D::Vector3& MinB = box.low(); + const G3D::Vector3& MaxB = box.high(); + G3D::Vector3 MaxT(-1.0f, -1.0f, -1.0f); + + // Find candidate planes. + for (int i = 0; i < 3; ++i) + { + if (origin[i] < MinB[i]) + { + location[i] = MinB[i]; + Inside = false; + + // Calculate T distances to candidate planes + if (IR(dir[i])) + { + MaxT[i] = (MinB[i] - origin[i]) / dir[i]; + } + } + else if (origin[i] > MaxB[i]) + { + location[i] = MaxB[i]; + Inside = false; + + // Calculate T distances to candidate planes + if (IR(dir[i])) + { + MaxT[i] = (MaxB[i] - origin[i]) / dir[i]; + } + } + } + + if (Inside) + { + // definite hit + location = origin; + return true; + } + + // Get largest of the maxT's for final choice of intersection + int WhichPlane = 0; + if (MaxT[1] > MaxT[WhichPlane]) + { + WhichPlane = 1; + } + + if (MaxT[2] > MaxT[WhichPlane]) + { + WhichPlane = 2; + } + + // Check final candidate actually inside box + if (IR(MaxT[WhichPlane]) & 0x80000000) + { + // Miss the box + return false; + } + + for (int i = 0; i < 3; ++i) + { + if (i != WhichPlane) + { + location[i] = origin[i] + MaxT[WhichPlane] * dir[i]; + if ((location[i] < MinB[i]) || + (location[i] > MaxB[i])) + { + // On this plane we're outside the box extents, so + // we miss the box + return false; + } + } + } + /* + // Choose the normal to be the plane normal facing into the ray + normal = G3D::Vector3::zero(); + normal[WhichPlane] = (dir[WhichPlane] > 0) ? -1.0 : 1.0; + */ + return true; + +#undef IR + } + }; +} +#endif diff --git a/src/server/shared/vmap/WorldModel.cpp b/src/server/shared/vmap/WorldModel.cpp new file mode 100644 index 00000000000..690c77577ae --- /dev/null +++ b/src/server/shared/vmap/WorldModel.cpp @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "WorldModel.h" +#include "VMapDefinitions.h" +#include "MapTree.h" + +using G3D::Vector3; +using G3D::Ray; + +template<> struct BoundsTrait<VMAP::GroupModel> +{ + static void getBounds(const VMAP::GroupModel& obj, G3D::AABox& out) { out = obj.GetBound(); } +}; + + +namespace VMAP +{ + bool IntersectTriangle(const MeshTriangle &tri, std::vector<Vector3>::const_iterator points, const G3D::Ray &ray, float &distance) + { + static const float EPS = 1e-5f; + + // See RTR2 ch. 13.7 for the algorithm. + + const Vector3 e1 = points[tri.idx1] - points[tri.idx0]; + const Vector3 e2 = points[tri.idx2] - points[tri.idx0]; + const Vector3 p(ray.direction().cross(e2)); + const float a = e1.dot(p); + + if (abs(a) < EPS) { + // Determinant is ill-conditioned; abort early + return false; + } + + const float f = 1.0f / a; + const Vector3 s(ray.origin() - points[tri.idx0]); + const float u = f * s.dot(p); + + if ((u < 0.0f) || (u > 1.0f)) { + // We hit the plane of the m_geometry, but outside the m_geometry + return false; + } + + const Vector3 q(s.cross(e1)); + const float v = f * ray.direction().dot(q); + + if ((v < 0.0f) || ((u + v) > 1.0f)) { + // We hit the plane of the triangle, but outside the triangle + return false; + } + + const float t = f * e2.dot(q); + + if ((t > 0.0f) && (t < distance)) + { + // This is a new hit, closer than the previous one + distance = t; + + /* baryCoord[0] = 1.0 - u - v; + baryCoord[1] = u; + baryCoord[2] = v; */ + + return true; + } + // This hit is after the previous hit, so ignore it + return false; + } + + class TriBoundFunc + { + public: + TriBoundFunc(std::vector<Vector3> &vert): vertices(vert.begin()) {} + void operator()(const MeshTriangle &tri, G3D::AABox &out) const + { + G3D::Vector3 lo = vertices[tri.idx0]; + G3D::Vector3 hi = lo; + + lo = (lo.min(vertices[tri.idx1])).min(vertices[tri.idx2]); + hi = (hi.max(vertices[tri.idx1])).max(vertices[tri.idx2]); + + out = G3D::AABox(lo, hi); + } + protected: + const std::vector<Vector3>::const_iterator vertices; + }; + + // ===================== WmoLiquid ================================== + + WmoLiquid::WmoLiquid(uint32 width, uint32 height, const Vector3 &corner, uint32 type): + iTilesX(width), iTilesY(height), iCorner(corner), iType(type) + { + iHeight = new float[(width+1)*(height+1)]; + iFlags = new uint8[width*height]; + } + + WmoLiquid::WmoLiquid(const WmoLiquid &other): iHeight(0), iFlags(0) + { + *this = other; // use assignment operator... + } + + WmoLiquid::~WmoLiquid() + { + delete[] iHeight; + delete[] iFlags; + } + + WmoLiquid& WmoLiquid::operator=(const WmoLiquid &other) + { + if (this == &other) + return *this; + iTilesX = other.iTilesX; + iTilesY = other.iTilesY; + iCorner = other.iCorner; + iType = other.iType; + delete iHeight; + delete iFlags; + if (other.iHeight) + { + iHeight = new float[(iTilesX+1)*(iTilesY+1)]; + memcpy(iHeight, other.iHeight, (iTilesX+1)*(iTilesY+1)*sizeof(float)); + } + else + iHeight = 0; + if (other.iFlags) + { + iFlags = new uint8[iTilesX * iTilesY]; + memcpy(iFlags, other.iFlags, iTilesX * iTilesY); + } + else + iFlags = 0; + return *this; + } + + bool WmoLiquid::GetLiquidHeight(const Vector3 &pos, float &liqHeight) const + { + uint32 tx = (pos.x - iCorner.x)/LIQUID_TILE_SIZE; + if (tx<0 || tx >= iTilesX) return false; + uint32 ty = (pos.y - iCorner.y)/LIQUID_TILE_SIZE; + if (ty<0 || ty >= iTilesY) return false; + // checking for 0x08 *might* be enough, but disabled tiles always are 0x?F: + if ((iFlags[tx + ty*iTilesX] & 0x0F) == 0x0F) + return false; + //placeholder...use only lower left corner vertex + liqHeight = /* iCorner.z + */ iHeight[tx + ty*(iTilesX+1)]; + return true; + } + + uint32 WmoLiquid::GetFileSize() + { + return 2 * sizeof(uint32) + + sizeof(Vector3) + + (iTilesX + 1)*(iTilesY + 1) * sizeof(float) + + iTilesX * iTilesY; + } + + bool WmoLiquid::writeToFile(FILE *wf) + { + bool result = true; + if (result && fwrite(&iTilesX, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&iTilesY, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&iCorner, sizeof(Vector3), 1, wf) != 1) result = false; + if (result && fwrite(&iType, sizeof(uint32), 1, wf) != 1) result = false; + uint32 size = (iTilesX + 1)*(iTilesY + 1); + if (result && fwrite(iHeight, sizeof(float), size, wf) != size) result = false; + size = iTilesX*iTilesY; + if (result && fwrite(iFlags, sizeof(uint8), size, wf) != size) result = false; + return result; + } + + bool WmoLiquid::readFromFile(FILE *rf, WmoLiquid *&out) + { + bool result = true; + WmoLiquid *liquid = new WmoLiquid(); + if (result && fread(&liquid->iTilesX, sizeof(uint32), 1, rf) != 1) result = false; + if (result && fread(&liquid->iTilesY, sizeof(uint32), 1, rf) != 1) result = false; + if (result && fread(&liquid->iCorner, sizeof(Vector3), 1, rf) != 1) result = false; + if (result && fread(&liquid->iType, sizeof(uint32), 1, rf) != 1) result = false; + uint32 size = (liquid->iTilesX + 1)*(liquid->iTilesY + 1); + liquid->iHeight = new float[size]; + if (result && fread(liquid->iHeight, sizeof(float), size, rf) != size) result = false; + size = liquid->iTilesX * liquid->iTilesY; + liquid->iFlags = new uint8[size]; + if (result && fread(liquid->iFlags, sizeof(uint8), size, rf) != size) result = false; + if (!result) + delete liquid; + out = liquid; + return result; + } + + // ===================== GroupModel ================================== + + GroupModel::GroupModel(const GroupModel &other): + iBound(other.iBound), iMogpFlags(other.iMogpFlags), iGroupWMOID(other.iGroupWMOID), + vertices(other.vertices), triangles(other.triangles), meshTree(other.meshTree), iLiquid(0) + { + if (other.iLiquid) + iLiquid = new WmoLiquid(*other.iLiquid); + } + + void GroupModel::setMeshData(std::vector<Vector3> &vert, std::vector<MeshTriangle> &tri) + { + vertices.swap(vert); + triangles.swap(tri); + TriBoundFunc bFunc(vertices); + meshTree.build(triangles, bFunc); + } + + bool GroupModel::writeToFile(FILE *wf) + { + bool result = true; + uint32 chunkSize, count; + + if (result && fwrite(&iBound, sizeof(G3D::AABox), 1, wf) != 1) result = false; + if (result && fwrite(&iMogpFlags, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&iGroupWMOID, sizeof(uint32), 1, wf) != 1) result = false; + + // write vertices + if (result && fwrite("VERT", 1, 4, wf) != 4) result = false; + count = vertices.size(); + chunkSize = sizeof(uint32)+ sizeof(Vector3)*count; + if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false; + if (!count) // models without (collision) geometry end here, unsure if they are useful + return result; + if (result && fwrite(&vertices[0], sizeof(Vector3), count, wf) != count) result = false; + + // write triangle mesh + if (result && fwrite("TRIM", 1, 4, wf) != 4) result = false; + count = triangles.size(); + chunkSize = sizeof(uint32)+ sizeof(MeshTriangle)*count; + if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&triangles[0], sizeof(MeshTriangle), count, wf) != count) result = false; + + // write mesh BIH + if (result && fwrite("MBIH", 1, 4, wf) != 4) result = false; + if (result) result = meshTree.writeToFile(wf); + + // write liquid data + if (result && fwrite("LIQU", 1, 4, wf) != 4) result = false; + if (!iLiquid) + { + chunkSize = 0; + if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false; + return result; + } + chunkSize = iLiquid->GetFileSize(); + if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false; + if (result) result = iLiquid->writeToFile(wf); + + return result; + } + + bool GroupModel::readFromFile(FILE *rf) + { + char chunk[8]; + bool result = true; + uint32 chunkSize, count; + triangles.clear(); + vertices.clear(); + delete iLiquid; + iLiquid = 0; + + if (result && fread(&iBound, sizeof(G3D::AABox), 1, rf) != 1) result = false; + if (result && fread(&iMogpFlags, sizeof(uint32), 1, rf) != 1) result = false; + if (result && fread(&iGroupWMOID, sizeof(uint32), 1, rf) != 1) result = false; + + // read vertices + if (result && !readChunk(rf, chunk, "VERT", 4)) result = false; + if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false; + if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false; + if (!count) // models without (collision) geometry end here, unsure if they are useful + return result; + if (result) vertices.resize(count); + if (result && fread(&vertices[0], sizeof(Vector3), count, rf) != count) result = false; + + // read triangle mesh + if (result && !readChunk(rf, chunk, "TRIM", 4)) result = false; + if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false; + if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false; + if (result) triangles.resize(count); + if (result && fread(&triangles[0], sizeof(MeshTriangle), count, rf) != count) result = false; + + // read mesh BIH + if (result && !readChunk(rf, chunk, "MBIH", 4)) result = false; + if (result) result = meshTree.readFromFile(rf); + + // write liquid data + if (result && !readChunk(rf, chunk, "LIQU", 4)) result = false; + if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false; + if (result && chunkSize > 0) + result = WmoLiquid::readFromFile(rf, iLiquid); + return result; + } + + struct GModelRayCallback + { + GModelRayCallback(const std::vector<MeshTriangle> &tris, const std::vector<Vector3> &vert): + vertices(vert.begin()), triangles(tris.begin()), hit(false) {} + bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool pStopAtFirstHit) + { + bool result = IntersectTriangle(triangles[entry], vertices, ray, distance); + if (result) hit=true; + return hit; + } + std::vector<Vector3>::const_iterator vertices; + std::vector<MeshTriangle>::const_iterator triangles; + bool hit; + }; + + bool GroupModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const + { + if (!triangles.size()) + return false; + GModelRayCallback callback(triangles, vertices); + meshTree.intersectRay(ray, callback, distance, stopAtFirstHit); + return callback.hit; + } + + bool GroupModel::IsInsideObject(const Vector3 &pos, const Vector3 &down, float &z_dist) const + { + if (!triangles.size() || !iBound.contains(pos)) + return false; + GModelRayCallback callback(triangles, vertices); + Vector3 rPos = pos - 0.1f * down; + float dist = G3D::inf(); + G3D::Ray ray(rPos, down); + bool hit = IntersectRay(ray, dist, false); + if (hit) + z_dist = dist - 0.1f; + return hit; + } + + bool GroupModel::GetLiquidLevel(const Vector3 &pos, float &liqHeight) const + { + if (iLiquid) + return iLiquid->GetLiquidHeight(pos, liqHeight); + return false; + } + + uint32 GroupModel::GetLiquidType() const + { + // convert to type mask, matching MAP_LIQUID_TYPE_* defines in Map.h + if (iLiquid) + return (1 << iLiquid->GetType()); + return 0; + } + + // ===================== WorldModel ================================== + + void WorldModel::setGroupModels(std::vector<GroupModel> &models) + { + groupModels.swap(models); + groupTree.build(groupModels, BoundsTrait<GroupModel>::getBounds, 1); + } + + struct WModelRayCallBack + { + WModelRayCallBack(const std::vector<GroupModel> &mod): models(mod.begin()), hit(false) {} + bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool pStopAtFirstHit) + { + bool result = models[entry].IntersectRay(ray, distance, pStopAtFirstHit); + if (result) hit=true; + return hit; + } + std::vector<GroupModel>::const_iterator models; + bool hit; + }; + + bool WorldModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const + { + // small M2 workaround, maybe better make separate class with virtual intersection funcs + // in any case, there's no need to use a bound tree if we only have one submodel + if (groupModels.size() == 1) + return groupModels[0].IntersectRay(ray, distance, stopAtFirstHit); + + WModelRayCallBack isc(groupModels); + groupTree.intersectRay(ray, isc, distance, stopAtFirstHit); + return isc.hit; + } + + class WModelAreaCallback { + public: + WModelAreaCallback(const std::vector<GroupModel> &vals, const Vector3 &down): + prims(vals.begin()), hit(vals.end()), minVol(G3D::inf()), zDist(G3D::inf()), zVec(down) {} + std::vector<GroupModel>::const_iterator prims; + std::vector<GroupModel>::const_iterator hit; + float minVol; + float zDist; + Vector3 zVec; + void operator()(const Vector3& point, uint32 entry) + { + float group_Z; + //float pVol = prims[entry].GetBound().volume(); + //if(pVol < minVol) + //{ + /* if (prims[entry].iBound.contains(point)) */ + if (prims[entry].IsInsideObject(point, zVec, group_Z)) + { + //minVol = pVol; + //hit = prims + entry; + if (group_Z < zDist) + { + zDist = group_Z; + hit = prims + entry; + } +#ifdef VMAP_DEBUG + const GroupModel &gm = prims[entry]; + printf("%10u %8X %7.3f,%7.3f,%7.3f | %7.3f,%7.3f,%7.3f | z=%f, p_z=%f\n", gm.GetWmoID(), gm.GetMogpFlags(), + gm.GetBound().low().x, gm.GetBound().low().y, gm.GetBound().low().z, + gm.GetBound().high().x, gm.GetBound().high().y, gm.GetBound().high().z, group_Z, point.z); +#endif + } + //} + //std::cout << "trying to intersect '" << prims[entry].name << "'\n"; + } + }; + + bool WorldModel::IntersectPoint(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, AreaInfo &info) const + { + if (!groupModels.size()) + return false; + WModelAreaCallback callback(groupModels, down); + groupTree.intersectPoint(p, callback); + if (callback.hit != groupModels.end()) + { + info.rootId = RootWMOID; + info.groupId = callback.hit->GetWmoID(); + info.flags = callback.hit->GetMogpFlags(); + info.result = true; + dist = callback.zDist; + return true; + } + return false; + } + + bool WorldModel::GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const + { + if (!groupModels.size()) + return false; + WModelAreaCallback callback(groupModels, down); + groupTree.intersectPoint(p, callback); + if (callback.hit != groupModels.end()) + { + info.hitModel = &(*callback.hit); + dist = callback.zDist; + return true; + } + return false; + } + + bool WorldModel::writeFile(const std::string &filename) + { + FILE *wf = fopen(filename.c_str(), "wb"); + if (!wf) + return false; + + bool result = true; + uint32 chunkSize, count; + result = fwrite(VMAP_MAGIC,1,8,wf) == 8; + if (result && fwrite("WMOD", 1, 4, wf) != 4) result = false; + chunkSize = sizeof(uint32) + sizeof(uint32); + if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&RootWMOID, sizeof(uint32), 1, wf) != 1) result = false; + + // write group models + count=groupModels.size(); + if (count) + { + if (result && fwrite("GMOD", 1, 4, wf) != 4) result = false; + //chunkSize = sizeof(uint32)+ sizeof(GroupModel)*count; + //if (result && fwrite(&chunkSize, sizeof(uint32), 1, wf) != 1) result = false; + if (result && fwrite(&count, sizeof(uint32), 1, wf) != 1) result = false; + for (uint32 i=0; i<groupModels.size() && result; ++i) + result = groupModels[i].writeToFile(wf); + + // write group BIH + if (result && fwrite("GBIH", 1, 4, wf) != 4) result = false; + if (result) result = groupTree.writeToFile(wf); + } + + fclose(wf); + return result; + } + + bool WorldModel::readFile(const std::string &filename) + { + FILE *rf = fopen(filename.c_str(), "rb"); + if (!rf) + return false; + + bool result = true; + uint32 chunkSize, count; + char chunk[8]; // Ignore the added magic header + if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) result = false; + + if (result && !readChunk(rf, chunk, "WMOD", 4)) result = false; + if (result && fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false; + if (result && fread(&RootWMOID, sizeof(uint32), 1, rf) != 1) result = false; + + // read group models + if (result && readChunk(rf, chunk, "GMOD", 4)) + { + //if (fread(&chunkSize, sizeof(uint32), 1, rf) != 1) result = false; + + if (result && fread(&count, sizeof(uint32), 1, rf) != 1) result = false; + if (result) groupModels.resize(count); + //if (result && fread(&groupModels[0], sizeof(GroupModel), count, rf) != count) result = false; + for (uint32 i=0; i<count && result; ++i) + result = groupModels[i].readFromFile(rf); + + // read group BIH + if (result && !readChunk(rf, chunk, "GBIH", 4)) result = false; + if (result) result = groupTree.readFromFile(rf); + } + + fclose(rf); + return result; + } +} diff --git a/src/server/shared/vmap/WorldModel.h b/src/server/shared/vmap/WorldModel.h new file mode 100644 index 00000000000..f12efed4f5d --- /dev/null +++ b/src/server/shared/vmap/WorldModel.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WORLDMODEL_H +#define _WORLDMODEL_H + +#include <G3D/HashTrait.h> +#include <G3D/Vector3.h> +#include <G3D/AABox.h> +#include <G3D/Ray.h> +#include "BIH.h" + +#include "Platform/Define.h" + +namespace VMAP +{ + class TreeNode; + struct AreaInfo; + struct LocationInfo; + + class MeshTriangle + { + public: + MeshTriangle(){}; + MeshTriangle(uint32 na, uint32 nb, uint32 nc): idx0(na), idx1(nb), idx2(nc) {}; + + uint32 idx0; + uint32 idx1; + uint32 idx2; + }; + + class WmoLiquid + { + public: + WmoLiquid(uint32 width, uint32 height, const Vector3 &corner, uint32 type); + WmoLiquid(const WmoLiquid &other); + ~WmoLiquid(); + WmoLiquid& operator=(const WmoLiquid &other); + bool GetLiquidHeight(const Vector3 &pos, float &liqHeight) const; + uint32 GetType() const { return iType; } + float *GetHeightStorage() { return iHeight; } + uint8 *GetFlagsStorage() { return iFlags; } + uint32 GetFileSize(); + bool writeToFile(FILE *wf); + static bool readFromFile(FILE *rf, WmoLiquid *&liquid); + private: + WmoLiquid(): iHeight(0), iFlags(0) {}; + uint32 iTilesX; //!< number of tiles in x direction, each + uint32 iTilesY; + Vector3 iCorner; //!< the lower corner + uint32 iType; //!< liquid type + float *iHeight; //!< (tilesX + 1)*(tilesY + 1) height values + uint8 *iFlags; //!< info if liquid tile is used + }; + + /*! holding additional info for WMO group files */ + class GroupModel + { + public: + GroupModel(): iLiquid(0) {} + GroupModel(const GroupModel &other); + GroupModel(uint32 mogpFlags, uint32 groupWMOID, const AABox &bound): + iBound(bound), iMogpFlags(mogpFlags), iGroupWMOID(groupWMOID), iLiquid(0) {} + ~GroupModel() { delete iLiquid; } + + //! pass mesh data to object and create BIH. Passed vectors get get swapped with old geometry! + void setMeshData(std::vector<Vector3> &vert, std::vector<MeshTriangle> &tri); + void setLiquidData(WmoLiquid *liquid) { iLiquid = liquid; } + bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const; + bool IsInsideObject(const Vector3 &pos, const Vector3 &down, float &z_dist) const; + bool GetLiquidLevel(const Vector3 &pos, float &liqHeight) const; + uint32 GetLiquidType() const; + bool writeToFile(FILE *wf); + bool readFromFile(FILE *rf); + const G3D::AABox& GetBound() const { return iBound; } + uint32 GetMogpFlags() const { return iMogpFlags; } + uint32 GetWmoID() const { return iGroupWMOID; } + protected: + G3D::AABox iBound; + uint32 iMogpFlags;// 0x8 outdor; 0x2000 indoor + uint32 iGroupWMOID; + std::vector<Vector3> vertices; + std::vector<MeshTriangle> triangles; + BIH meshTree; + WmoLiquid *iLiquid; + }; + /*! Holds a model (converted M2 or WMO) in its original coordinate space */ + class WorldModel + { + public: + WorldModel(): RootWMOID(0) {} + + //! pass group models to WorldModel and create BIH. Passed vector is swapped with old geometry! + void setGroupModels(std::vector<GroupModel> &models); + void setRootWmoID(uint32 id) { RootWMOID = id; } + bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const; + bool IntersectPoint(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, AreaInfo &info) const; + bool GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const; + bool writeFile(const std::string &filename); + bool readFile(const std::string &filename); + protected: + uint32 RootWMOID; + std::vector<GroupModel> groupModels; + BIH groupTree; + }; +} // namespace VMAP + +#endif // _WORLDMODEL_H |
