Compare commits

..

1021 commits

Author SHA1 Message Date
David Cernat
8aad93b904
Merge pull request #519 from TES3MP/0.7.0-alpha
[General] Update positions for dead players on other clients
2019-03-24 03:54:43 +02:00
David Cernat
3effd5f1ff [General] Update positions for dead players on other clients
Dead players will now show up at the correct cell and position for living players, making server scripts that allow players to revive each other much more functional.
2019-03-24 03:52:05 +02:00
David Cernat
4692f29b9d
Merge pull request #517 from uramer/0.7.0markers
update player map markers when client changes cell
2019-03-22 21:39:06 +02:00
David Cernat
03d377ec54
Merge pull request #518 from TES3MP/0.7.0-alpha
[General] Rename CellReplace packet into CellReset
2019-03-22 21:36:07 +02:00
David Cernat
8ff2d1b829 [General] Rename CellReplace packet into CellReset 2019-03-22 21:33:34 +02:00
David Cernat
cb82318c36 [General] Fix problems with Utils::getArchitectureType() 2019-03-22 03:09:11 +02:00
uramer
3b2098382b update player map markers when client changes cell 2019-03-21 16:27:15 +01:00
David Cernat
cb5e24e6c5
Merge pull request #516 from TES3MP/0.7.0-alpha
[Server] Add GetMillisecondsSinceServerStart() server function
2019-03-20 20:05:30 +02:00
David Cernat
91f82d845c [Server] Add GetMillisecondsSinceServerStart() server function 2019-03-20 20:02:31 +02:00
David Cernat
d35026bbf5
Merge pull request #515 from TES3MP/0.7.0-alpha
0.7.0 alpha
2019-03-20 18:58:31 +02:00
David Cernat
bd677726bf [Server] Add StatsFunctions that get/set damage to attributes/skills 2019-03-20 18:54:35 +02:00
David Cernat
9fc4c83858 [Client] Send skill/attribute packets when skills/attributes are damaged 2019-03-20 18:40:46 +02:00
David Cernat
ece39748de [Server] Fix typo causing recursion in deprecated actor list function 2019-03-20 17:01:21 +02:00
David Cernat
5c4d3df551 [Server] Deprecate DoesFileExist(), add DoesFilePathExist() 2019-03-19 04:52:58 +02:00
David Cernat
2cdabddc0e [Server] Move most MiscellaneousFunctions to ServerFunctions 2019-03-19 04:25:33 +02:00
David Cernat
b46767de6e [Server] Clean up recent additions to ServerFunctions 2019-03-19 03:57:16 +02:00
David Cernat
911079e0bc
Merge pull request #512 from TES3MP/0.7.0-alpha
0.7.0 alpha
2019-03-12 05:38:36 +02:00
David Cernat
331fa86844 [Server] Call OnServerPostInit after OnRequestDataFileList
This allows different actions to be taken in OnServerPostInit based on what the data files being used are.
2019-03-12 05:36:33 +02:00
David Cernat
a0ec9dfd2e [Server] Rename OnRequestPluginList into OnRequestDataFileList 2019-03-12 03:18:57 +02:00
David Cernat
986528c67d [Server] Add error message as argument to OnServerScriptCrash 2019-03-12 02:15:20 +02:00
David Cernat
552a94a0ca [Server] Add OnServerScriptCrash script event 2019-03-10 00:46:40 +02:00
David Cernat
a508a0faf8 [Server] Turn GetArguments() from ScriptFunctions into Utils function 2019-02-24 01:43:04 +02:00
David Cernat
dcbc9d1831 [Client] Print cells for actor deaths 2019-02-21 21:51:02 +02:00
David Cernat
828c52138f [Documentation] Update readme and credits
According to some legal advice I've received, the "TES3MP Team" is too ambiguous of a legal entity, so – with Koncord's agreement – the copyright is now assigned specifically to us, the project's developers.
2019-02-19 17:29:29 +02:00
David Cernat
69e7d3f2a7 [Documentation] Update credits 2019-02-14 13:07:54 +02:00
David Cernat
f3b8a5b909 [General] Check integrity of credits only on Windows clients
This avoids the problems that were encountered in Linux and macOS builds regarding this check while also still addressing the scenario where official Windows builds had their credits modified by people unrelated to the project.
2019-02-14 00:29:55 +02:00
David Cernat
a0ad0b29bc Merge branch '0.7.0' of https://github.com/TES3MP/openmw-tes3mp into 0.7.0 2019-02-13 21:57:24 +02:00
David Cernat
222837976c [Server] Fix type name warning for Player
The warning in Visual Studio was: "'Player': type name first seen using 'class' now seen using 'struct'"
2019-02-13 21:56:47 +02:00
Koncord
77386525f2 [General] Update Travis CI 2019-02-14 01:56:10 +08:00
David Cernat
c058dce346 [General] Clarify meaning of commit hash displayed on start 2019-01-31 13:39:06 +02:00
David Cernat
1df1515c7e [Client] Add logging for invalid enchantmentIds in RecordHelper 2019-01-23 01:04:59 +02:00
David Cernat
999ce857c7 [Client] Add logging for records ignored due to their invalid baseIds 2019-01-23 00:48:06 +02:00
David Cernat
db7e09f441 [Client] Use more consistent logging when reading dynamic record packets 2019-01-23 00:38:05 +02:00
David Cernat
0fa116b47d [Client] Remove useless lines in RecordHelper 2019-01-23 00:20:51 +02:00
Koncord
0df32accca [Server] Fix ARM build 2019-01-21 12:02:02 +08:00
David Cernat
fd40e8c971 [Client] Prevent ObjectState spam by not resending an already sent state 2019-01-15 14:26:00 +02:00
David Cernat
6e47b65205 [Client] Set attribute increases & level progress after correct packets
Originally, the PlayerSkill packet contained skills, attribute increases and level progress. In 78441c769a, the attribute increases were moved to the PlayerAttribute packet and the level progress was moved to the PlayerLevel packet, but – due to an oversight – attribute increases and level progress were still being applied to the local player only when a PlayerSkill packet was received, based on whatever values were stored from the last PlayerAttribute and PlayerLevel packets.
2019-01-11 14:26:13 +02:00
David Cernat
f481c85e07 [Client] Use ADD before REMOVE for PlayerInventory in repair/recharge
Previously, when recharging or repairing an item, the client sent a PlayerInventory packet to the server with the old version of the item that was supposed to be removed and then it sent a PlayerInventory packet with the new version of the item that was supposed to be added.

Unfortunately, the current CoreScripts make it so custom items using generated IDs have their records deleted when they are completely removed from the world, however briefly, even if they are added back immediately afterwards. In practice, this meant that – before this commit – recharging or repairing a custom item led to its removal from the player inventory stored on the server, followed by the deletion of its record, followed by its readdition to the inventory (but with the record staying deleted). Logging out and logging back in immediately prevented the player from receiving the item anymore because of its now non-existent record.
2019-01-11 13:08:26 +02:00
David Cernat
8a99f215f6 [Client] Add LocalPlayer::sendItemChange() variant with mwmp::Item arg 2019-01-11 12:54:47 +02:00
David Cernat
db9c1b9882 [Client] Add MechanicsHelper::getItem() for getting mwmp::Item from Ptr 2019-01-11 12:53:26 +02:00
David Cernat
799241e8c6 [Client] Use informative error message for RefData::setCount() issue 2019-01-11 08:16:29 +02:00
David Cernat
43f195f0c7 [Client] Use clearer debug for actor initializations 2019-01-05 23:27:35 +02:00
David Cernat
2e1d4a9449 [Server] Fix non-Windows builds 2019-01-05 22:11:58 +02:00
David Cernat
81e2e48561 [Client] Fix item magic casting synchronization for spell scrolls
Previously, spell scrolls were used up before their IDs could be included in attacks packets supposed to be sent for them.
2018-12-31 13:24:32 +02:00
David Cernat
d83160523f [Client] Add items required for item magic casting when they are missing 2018-12-31 06:55:35 +02:00
David Cernat
433a69a588 [Client] Send all data for newly initialized LocalActors at least once 2018-12-31 04:36:59 +02:00
David Cernat
e70fd2cf3a [Server] Accept clients with wrong password on servers with no password 2018-12-31 03:52:25 +02:00
David Cernat
eb52babf29 [Server] Print IP instead of name or PID for players unable to connect
The player name was always blank in such situations, providing no useful information. The PID was not useful in any way either.
2018-12-30 18:02:26 +02:00
David Cernat
e96091fd6b [General] Use more consistent variable names for password, address, etc. 2018-12-30 17:23:12 +02:00
David Cernat
906d2a837d [Client] Send PlayerInventory packets when recharging items w/ soulgems 2018-12-30 11:58:33 +02:00
David Cernat
71679934a1 [Client] Send PlayerInventory packets when repairing items 2018-12-30 09:39:46 +02:00
David Cernat
5d9893ee92 [Client] Set actor killer correctly for spells that do damage over time
Additionally, clean up comments related to other code that sets actor killers.
2018-12-30 07:40:11 +02:00
David Cernat
6e1504f0a1 [Server] Use clearer variable & function names in TimerAPI 2018-12-30 04:15:53 +02:00
David Cernat
42b5a8054f [Server] Remove unusable position functions for players 2018-12-30 03:17:37 +02:00
Koncord
4ce0331f1b [Server] Fix GCC build 2018-12-29 15:54:08 +08:00
Koncord
9343b8af2f [Server] Remove unused function 2018-12-29 14:02:08 +08:00
Koncord
c2230a8a21 [Server] Add MP flag to the server if enabled 2018-12-29 12:03:01 +08:00
Koncord
a0e89208a0 [General] Fix standalone server build 2018-12-29 11:58:49 +08:00
Koncord
55cea491ca [Server] Introduce MS VC++ 2017 support 2018-12-29 11:57:26 +08:00
Koncord
6af2400752 [Server] Remove usages of get/set env. Add GetModDir function 2018-12-29 11:40:31 +08:00
Koncord
b3456a8841 [Server] Fix invalidation of iterators 2018-12-29 11:10:20 +08:00
David Cernat
343dd8b5ea [Client] Fix addition of items to player inventories
Previously, multiple stacks of the same item ID could overwrite data in each other because of how the logic in ContainerStore::add() works. For example, a stack of 5 grand soul gems with no souls would get added to the player, then the attempt to add a grand soul gem with a particular soul would retrieve the previous stack first before setting all of it to that soul, resulting in 6 grand soul gems with that soul.
2018-12-26 13:41:19 +02:00
David Cernat
76ac905efc [Client] Send PlayerInventory packets when trapping souls in soulgems 2018-12-26 12:25:00 +02:00
David Cernat
f853368641 [Client] Fix loss of player items in ContainerStore::unstack()
Previously, unstacking items for a player led to a PlayerInventory packet being sent about the items' removal.

This change makes it so both a packet about their re-addition and their removal are sent instead, cancelling each other out, which is inelegant, but arguably preferable to complicating the sending of PlayerInventory packets again.
2018-12-26 12:24:26 +02:00
David Cernat
5e38e8abdb [Server] Add GetArchitectureType() script function
Additionally, bring GetOperatingSystem() up-to-date by making it use the renamed function in Utils.
2018-12-17 11:55:50 +02:00
David Cernat
9fe54aa8c6 [General] Add getArchitectureType() to multiplayer Utils
Additionally, rename getOperatingSystem() into getOperatingSystemType() for clarity.
2018-12-17 11:46:51 +02:00
David Cernat
fa1700e2ab [Server] Add GetOperatingSystemType() script function 2018-12-17 11:32:31 +02:00
David Cernat
da6b89c185 [General] Add getOperatingSystem() to multiplayer Utils 2018-12-17 10:47:34 +02:00
David Cernat
50714599d9 [Client] Spawn at exterior 0, -7 by default 2018-12-17 08:25:22 +02:00
David Cernat
afd17e5a48 [Client] Don't finish drag & drop that is supposed to be unsuccessful
This prevents items from vanishing when your attempt to drop them in a full container is denied.
2018-12-06 18:11:52 +02:00
David Cernat
a6c6db89fc [Client] Send object packets when scripts use PlaceItem/PlaceItemCell 2018-12-05 01:56:27 +02:00
David Cernat
d05a82a734 [Client] Avoid repetitive code when unequipping items in resurrection 2018-12-04 03:55:03 +02:00
David Cernat
b5b26c6685
Merge pull request #492 from terabyte25/patch-7
[Client] Disallow opening inventory menu when not logged in
2018-12-01 23:17:05 +02:00
terrabyte25
35755eb1f1
[Client] Disallow opening inventory menu when not logged in 2018-12-01 10:51:33 -06:00
David Cernat
b7090b2550 [Server] Add experimental option for not crashing from Lua script errors
Additionally, fix return type of GetPluginEnforcementState()
2018-12-01 03:03:39 +02:00
David Cernat
b39e3f518b [Client] Use correct log levels for inventory and dynamic record packets 2018-11-30 23:38:16 +02:00
David Cernat
d8ca268067 [Server] Move plugin enforcement functions to ServerFunctions 2018-11-30 22:43:10 +02:00
David Cernat
2933526995 [Server] Include errors related to Lua calls in server logs 2018-11-30 22:01:02 +02:00
David Cernat
ef80894c5c
Merge pull request #486 from testman42/patch-2
Use more descriptive terminology for chat modes
2018-11-17 23:19:17 +02:00
Testman
6b3f598837
Use more descriptive terminology for chat modes
Changed "Chat disabled" to "Chat hidden", "Chat enabled" to "Chat visible" and "Chat in hidden mode" to "Chat appearing when needed".
2018-11-17 16:54:14 +01:00
David Cernat
eb3ae95f0e [Documentation] Display build status for correct branch 2018-11-16 06:40:21 +02:00
David Cernat
d3eb106c3b [Documentation] Update readme for current situation 2018-11-16 04:49:14 +02:00
David Cernat
e834a4ec74 [Client] Find closest enchantmentCharge in getItemPtrFromStore()
Enchanted inventory items continuously recharge their enchantment charges, which getItemPtrFromStore() should account for.

Additionally, prevent framelistener errors caused by PlayerItemUse packets about non-existent items.
2018-11-13 20:36:31 +02:00
David Cernat
bc7bcae190
Merge pull request #484 from GrimKriegor/0.7.0
[General] Change the default plugins home location
2018-11-12 07:11:37 +02:00
Grim Kriegor
8f90f8a3b8 [General] Change the default plugins home location 2018-11-12 01:10:10 +00:00
Koncord
e162af0003 [Server] Disallow non void callbacks 2018-10-30 15:32:52 +08:00
Koncord
07a5f5296c [Server] Rework OnRequestPluginList callback. Add AddPluginHash function 2018-10-30 14:56:54 +08:00
Koncord
20a7619a4a [Server] Remove result from the OnPlayerConnect callback
Now it's recommended to use tes3mp.Kick() function
2018-10-30 13:18:32 +08:00
Koncord
f1e8569291 [Server] Remove result from the OnPlayerSendMessage callback 2018-10-30 13:13:07 +08:00
Koncord
efa362031e [Server] Remove unused Main callback 2018-10-30 13:03:37 +08:00
Koncord
b83e4056a8 [Server] Remove CallFF dependency as it not fully supported by Windows and MacOS 2018-10-30 12:59:47 +08:00
Koncord
585557ad8a [Server] Remove argument cast in the Call with va_args 2018-10-30 12:58:15 +08:00
Koncord
3101de5f02 [Server] Add kicked load status 2018-10-30 12:56:50 +08:00
Koncord
e5e13b21ae [Client] Fix crash on drag&drop 2018-10-28 16:56:04 +08:00
David Cernat
c65d6c1328 [Client] Disable mListener methods in mwworld/containerstore
This should put an end to frequent crashes until I can fix the problem properly.
2018-10-27 02:19:45 +03:00
David Cernat
1baf82db32 [Client] Avoid PlayerSpellbook packet spam in some mods 2018-10-26 19:07:35 +03:00
David Cernat
d9bc1abf48 [Client] Don't send ObjectScale packets if not logged in 2018-10-26 02:33:47 +03:00
David Cernat
a8cf1e02c4 [Client] Allow unilateral scripted container changes not from console
This prevents infinite loops in certain client scripts from mods that use while loops to determine that all items of a certain type have been removed from a container, such as in the script BCSwap2Arg from  Better_Clothes.
2018-10-25 22:38:45 +03:00
David Cernat
99f8ef88a5 [Server] Add SetObjectActivatingPid() script function 2018-10-22 16:25:50 +03:00
David Cernat
17f13872aa [Client] Use forceUpdate correctly in LocalPlayer::updateStatsDynamic()
Previously, the forceUpdate argument was useless, preventing dynamic stats from being sent by certain newly created characters.
2018-10-22 13:22:23 +03:00
David Cernat
bfd7c83c4d [Client] Fix backwards logic when setting type for AI attacks 2018-10-16 21:18:41 +03:00
David Cernat
d9dd7073cf [General] Send certain packets only when logged in
Previously, client mods adding packet-sending scripts to the spawn area made clients send the associated packets as soon as they inputted their character name when joining a server using those mods. This made the clients either get disconnected for not replying to a handshake first, or it made them get kicked for sending object packets that are disallowed for players who are not logged in.

To fix this, LocalPlayer's hasFinishedCharGen() has been replaced with isLoggedIn(), because the former was already returning true when players inputted their names.
2018-10-13 15:36:13 +03:00
David Cernat
66d666d60c [Client] Use less confusing terminology when displaying plugin mismatch 2018-10-13 14:40:49 +03:00
David Cernat
bb834748c5 [Server] Log player kicks 2018-10-13 09:34:29 +03:00
David Cernat
a3111fbcc1 [Server] Use clearer error message when failing to bind port 2018-10-13 08:35:07 +03:00
David Cernat
3d40a162bc
Merge pull request #476 from SamHellawell/0.7.0-fix-equipcrash-linux-cleanup
Cleanup fix for equip item crash on Linux
2018-10-11 22:52:24 +03:00
Sam Hellawell
df1667b6e4 Cleanup fix for equip item crash on Linux
Signed-off-by: Sam Hellawell <sshellawell@gmail.com>
2018-10-11 21:49:24 +01:00
David Cernat
db2b3e95b8
Merge pull request #475 from SamHellawell/0.7.0-fix-equipcrash-linux
Fix crash when equipping item on linux
2018-10-11 22:40:09 +03:00
Sam Hellawell
1e171ad9fd Fix crash when equipping item on linux
Signed-off-by: Sam Hellawell <sshellawell@gmail.com>
2018-10-11 20:13:22 +01:00
David Cernat
e402a17757 [Client] Don't cast non-weapons to weapons in isUsingRangedWeapon()
This makes lockpicks and probes work again.
2018-10-09 09:54:13 +03:00
David Cernat
292536439e [Server] Rename script functions for clearing packet vectors for players 2018-10-03 02:26:47 +03:00
David Cernat
c79660f721 [Server] Make inventory script functions consistent with others
Functions that add elements to a vector should not change the action. This fixes the last remaining oddity in Koncord's original implementation of inventory sync.
2018-10-01 18:29:50 +03:00
David Cernat
8c7e06293f [Documentation] Update changelog with attack synchronization details 2018-09-26 02:48:52 +03:00
David Cernat
b76e00c66e [Server] Call OnPlayerCellChange script event near start of cell change
This makes it possible to send custom records used by players for their equipment before the hardcoded exchange of equipment packets takes place.

Additionally, remove the check for dead players because it has no real use and can potentially cause problems.
2018-09-26 02:40:21 +03:00
David Cernat
f100a660d4 [General] Fix ranged attack sync when using last throwing weapon or ammo 2018-09-24 11:30:53 +03:00
David Cernat
3f304866fd [Client] Use clearer variable names in DedicatedPlayer::setEquipment() 2018-09-24 10:11:42 +03:00
David Cernat
995d20348f [General] Always use correct ranged weapon & ammo for ranged attack sync
Previously, the player's currently selected weapon was being used in ranged attacks as in the original melee-oriented attack sync, which meant that shooting one type of projectile and then equipping another while the old projectile was still in the air turned the old projectile into the new projectile upon impact.

Additionally, avoid running most of the code in MechanicsHelper::assignAttackTarget() for non-hitting melee and ranged attacks.
2018-09-23 02:30:31 +03:00
David Cernat
db39c62e89 [Documentation] Update credits 2018-09-21 10:23:54 +03:00
David Cernat
b04ca28ece
Merge pull request #471 from testman42/patch-1
Update credits
2018-09-21 09:35:14 +03:00
David Cernat
b5f46ada73 [General] Synchronize projectile speed for ranged attacks
This is done by including the final attackStrength used for ranged attacks in packets and then applying it in WeaponAnimation::releaseArrow() on other clients.
2018-09-18 01:13:48 +03:00
David Cernat
7281f9fc42 [Client] Prevent unilateral paralysis of dedicated players & actors
This is a temporary workaround until active effect synchronization is implemented.
2018-09-16 15:34:57 +03:00
Testman
770d36ef67
Update credits
Reflect recent role changes
2018-09-15 17:00:13 +02:00
David Cernat
33a0886790 [Client] Fix synchronization of knockdown states 2018-09-15 04:59:06 +03:00
David Cernat
490303dc0b [Client] Clean up MechanicsHelper::processAttack() slightly
The debug is now more descriptive and some code is now skipped for non-ranged attacks.
2018-09-15 04:11:43 +03:00
David Cernat
9d2dc96a2e [Client] Use RANGED type for ranged attacks that haven't hit a target 2018-09-14 13:23:43 +03:00
David Cernat
af49f711ca [Client] Add isUsingRangedWeapon() method to MechanicsHelper 2018-09-14 13:21:45 +03:00
David Cernat
3f6ca6f22b [Client] Bring drawState fallback for actors up-to-date w/ attack types 2018-09-11 15:12:11 +03:00
David Cernat
9d2cf6629b [Client] Fix logic for hand-to-hand attack sync 2018-09-11 15:07:44 +03:00
David Cernat
fcd31bf4a6 [General] Fix problems with the synchronization of ranged attacks
Projectile hits now send Attack packets with RANGED attacks, and their success or failure is now synchronized.

Strike enchantments no longer require a valid victim to be synchronized.

Additional debug messages have been added for attacks.
2018-09-11 11:56:45 +03:00
David Cernat
31a9b77f34 [Client] Reset hitPosition in MechanicsHelper::resetAttack() 2018-09-10 12:34:33 +03:00
David Cernat
7d221509cd [Client] Move item magic hook to correct location
Previously, synchronization for strike enchantments was partially broken because it triggered the sending of ITEM_MAGIC attack packets, which are only supposed to be sent when a spell is cast from a magical inventory item.
2018-09-10 12:02:21 +03:00
David Cernat
c9ad411dd3 [Client] Fix logic for setting applyProjectileEnchantment in attack sync 2018-09-09 22:33:48 +03:00
David Cernat
8012d0d7b7 [General] Include hit position in PlayerAttack and ActorAttack packets 2018-09-08 05:29:49 +03:00
David Cernat
dcd4478028 [Client] Always stop sending weather updates when moving to an interior 2018-09-07 08:37:22 +03:00
David Cernat
113002ca19 [Client] Return early when processing actors that can't be initialized 2018-09-05 20:03:35 +03:00
Koncord
48f4792bc1 [Server] Add GetMaxPlayers, GetPort and HasPassword functions to API 2018-09-05 18:19:34 +08:00
David Cernat
3bd8aa82fe [General] Reduce inventory-sending hooks to just 2 in ContainerStore
Whenever an item is added to or removed from the player's ContainerStore, that player sends a PlayerInventory packet with just that addition or removal.

This eliminates all the unnecessary packet spam related to oversized PlayerInventory packets that had existed in one form or another since the initial implementation of inventory sync in 1b259e2d33

Additionally, move booleans from BasePlayer to LocalPlayer when they are only needed on the client, and make the usage of the isReceivingQuickKeys boolean consistent with the new isReceivingInventory boolean by having them both in the processors of their associated packets.
2018-08-28 05:01:52 +03:00
David Cernat
ee3fc4a303 [Documentation] Update changelog for 0.7.0 2018-08-25 16:04:22 +03:00
David Cernat
9e58cc82bd [Server] Set minimum updateRate when communicating with master server 2018-08-23 00:10:49 +03:00
David Cernat
be448e5b8e [General] Use more appropriate update rate in server config 2018-08-23 00:06:28 +03:00
David Cernat
d1fa57ac14 [General] Switch to new official master server port when using old one 2018-08-22 13:49:17 +03:00
David Cernat
0658d39eaa [General] Update ports used for master server in client & server config 2018-08-22 13:47:46 +03:00
David Cernat
03832f933b [Client] Send only individual items in PlayerInventory packets
For a long time, whenever a PlayerInventory packet was sent, it contained all the items in the player's inventory, because that's how Koncord originally implemented it and I always had too many other priorities to go back and rework it.

From now on, clients only send PlayerInventory packet with the one item added or removed, with the single exception being trading with merchants, where the entire inventory is still sent for the time being.
2018-08-21 10:10:06 +03:00
David Cernat
75a64a69c7 [Server] Add GetInventoryChangesAction() script function
Additionally, fix a typo in the description of GetSpellBookChangesAction()
2018-08-21 10:06:40 +03:00
David Cernat
45b011452e [Client] Combine methods for sending spell packets into a single one 2018-08-21 01:20:30 +03:00
David Cernat
140e0ed52c [Client] Also clear aiActors when clearing ActorList 2018-08-20 20:54:34 +03:00
David Cernat
aed4ca2fd2 [Client] Allow use of baseId for more record types
Additionally, don't allow new enchantment records to be created if they have no effects, to avoid a crash.
2018-08-20 15:24:20 +03:00
David Cernat
a083439139 Merge pull request #469 from davidcernat/master while resolving conflicts
# Conflicts:
#	apps/openmw/main.cpp
#	apps/openmw/mwbase/world.hpp
#	apps/openmw/mwdialogue/dialoguemanagerimp.cpp
#	apps/openmw/mwmechanics/actors.cpp
#	apps/openmw/mwscript/dialogueextensions.cpp
#	apps/openmw/mwworld/worldimp.hpp
2018-08-20 14:08:44 +03:00
David Cernat
7efee0e968 [Client] Fix GCC build 2018-08-20 10:15:30 +03:00
David Cernat
5bd2244898 [Client] Uninitialize DedicatedActors instantly in some situations
When LocalActors briefly become DedicatedActors as the result of a server script, the DedicatedActors are immediately uninitialized to avoid bugs like them jumping in place or rotating slightly.

Additionally, the playing of animations and sounds received in packets for DedicatedActors is no longer done during their next update, but is instead done instantly when the packets are received.
2018-08-16 03:50:41 +03:00
David Cernat
5fd4113978 [General] Implement sending of ActorSpeech packets from server scripts 2018-08-13 20:39:03 +03:00
David Cernat
338efdb705 [General] Fix issues with MechanicsHelper::getItemPtrFromStore() 2018-08-11 19:00:02 +03:00
David Cernat
aec0c5bd49 [Server] Make capitalization consistent for AI-related script functions 2018-08-11 18:57:36 +03:00
David Cernat
9598212aad [Client] Don't add bound items to inventory as a result of item packets
Additionally, don't include bound items when sending PlayerInventory packets.
2018-08-11 16:05:37 +03:00
David Cernat
a3b9274365 [Client] Make it possible to check if an item ID belongs to a bound item 2018-08-11 16:02:09 +03:00
David Cernat
a1933e7bc2 [Client] Don't declare variable twice in LocalPlayer's setEquipment()
The variable equipmentItem is identical to currentItem, so it should not have been added in commit 58a6a8c3bc

Addditionally, use a more descriptive variable name than "a" for item Ptrs.
2018-08-11 15:28:03 +03:00
Marc Zinnschlag
1cfc1f9bdb Merged pull request #1666 2018-08-10 12:23:17 +02:00
Marc Zinnschlag
0aedb3aada Merged puil request #1808 2018-08-10 12:22:13 +02:00
Marc Zinnschlag
b67b17010d Merged pull request #1826 2018-08-10 12:21:49 +02:00
Marc Zinnschlag
24212d58e8 Merged pull request #1861 2018-08-10 12:21:05 +02:00
Andrei Kortunov
ec9a1b0d05 Handle RootCollisionNode, attached to non-root node (bug #4311) 2018-08-10 11:11:40 +04:00
Andrei Kortunov
cde95979d0 Fix combat engagement for creatures 2018-08-10 09:29:01 +04:00
David Cernat
5d66a9bb66 [Client] Fix path to MechanicsHelper in ProcessorPlayerItemUse 2018-08-09 22:33:22 +03:00
David Cernat
8df08c7d10 [General] Implement PlayerItemUse packet
Players can no longer unilaterally use items on themselves in their inventory. When they try to use an item, they send a PlayerItemUse packet to the server with the item's details. A serverside script can then check the item and either send the packet back to make the item use go through or drop it.
2018-08-09 18:25:20 +03:00
Andrei Kortunov
780648b584 Do not reset idle animations if we do not have ammo 2018-08-09 16:39:46 +04:00
Andrei Kortunov
df577babe9 Increase priority of 1st-person weapon animations to avoid issues with animation blending 2018-08-09 16:39:20 +04:00
Andrei Kortunov
71bcc11ba5 Apply only crossbow reload animation to upper body 2018-08-09 16:37:08 +04:00
Andrei Kortunov
a0d0e5d2db Give jumping animations higher priority than movement ones 2018-08-09 16:19:03 +04:00
Andrei Kortunov
6a03aa6fdb Reduce jittering during turning animations for player 2018-08-09 16:19:00 +04:00
Andrei Kortunov
cd92014533 Do not touch GUI modes when taking screenshots (bug #4528) 2018-08-09 16:19:00 +04:00
Marc Zinnschlag
fe19d8ff35 Merged pull request #1857 2018-08-09 13:52:51 +02:00
Marc Zinnschlag
a2a57cf694 Merged pull request #1858 2018-08-09 13:51:31 +02:00
Marc Zinnschlag
0f510011b3 Merged pull request #1852 2018-08-09 13:49:50 +02:00
Marc Zinnschlag
cb62936949 Merged pull request #1853 2018-08-09 13:47:17 +02:00
Bret Curtis
03bf599426
Merge pull request #1856 from Capostrophic/hidden
Revert untextured shapes rendering changes
2018-08-09 12:36:03 +02:00
Bret Curtis
144f37f9b3
Merge pull request #1860 from akortunov/warningfix
Do not use fall-through to avoid GCC warnings
2018-08-09 10:00:09 +02:00
Andrei Kortunov
126b2fdd42 Use the isPlayer variable to do not check if the current actor is player every time 2018-08-09 11:16:19 +04:00
Bret Curtis
0d976f2c5e
Merge pull request #1859 from Capostrophic/debug
Fix a bunch of MSVC warnings
2018-08-09 09:12:41 +02:00
Andrei Kortunov
57e1462417 Do not use fall-through 2018-08-09 11:01:23 +04:00
Capostrophic
348c6f848e
Fix a bunch of MSVC warnings 2018-08-09 02:27:33 +03:00
Andrei Kortunov
51af729305 Do not use headtracking in the 1st-person view (bug #4573) 2018-08-08 23:29:03 +04:00
Andrei Kortunov
6202b4eca9 Do not touch GUI modes when taking screenshots (bug #4528) 2018-08-08 22:10:53 +04:00
Capostrophic
85208eff7f Revert untextured shapes rendering changes 2018-08-08 21:10:00 +03:00
Bret Curtis
0c0379c1ef
Merge pull request #1855 from OpenMW/allow_msvc2015_failure
Update appveyor.yml
2018-08-08 17:20:27 +02:00
Bret Curtis
97bc9954d0
Update appveyor.yml
allow msvc2015 to fail
2018-08-08 16:36:25 +02:00
Capostrophic
e9e9c0dd6b Fix guild guide fast travelling to exteriors time 2018-08-08 12:46:36 +03:00
Andrei Kortunov
b7859b3fa9 Cap underwater view distance (bug #4565) 2018-08-08 13:22:40 +04:00
Capostrophic
bcd9cc4baa Check the actor cell instead of the destination cell in fast travel price logic 2018-08-08 02:07:48 +03:00
Bret Curtis
a19d55e035
Merge pull request #1850 from Capostrophic/nodemask
Fix untextured shapes nodemask
2018-08-07 21:20:53 +02:00
Capostrophic
bda23c6ad6 Fix nodemask 2018-08-07 20:49:10 +03:00
Bret Curtis
a9729878d7
Merge pull request #1848 from Capostrophic/texturing
Don't render NiTriShapes without NiTexturingProperty (bug #4483)
2018-08-06 08:34:23 +02:00
Capostrophic
a1e3b2e586 Don't render NiTriShapes without NiTexturingProperty (bug #4483) 2018-08-05 16:24:24 +03:00
Marc Zinnschlag
b75b5d139a Merged pull request #1845 2018-08-05 12:28:38 +02:00
Marc Zinnschlag
7a93d118d2 Merged pull request #1846 2018-08-05 12:26:56 +02:00
Marc Zinnschlag
31491fdbde Merged pull request #1844 2018-08-05 12:25:10 +02:00
Capostrophic
7087bad580 Use special behavior for all topics with reserved names (bug #4557) 2018-08-05 12:39:53 +03:00
Andrei Kortunov
1f4dd3b393 Make partial binary search case insensitive, as it supposed to be (bug #4558) 2018-08-05 13:26:12 +04:00
David Cernat
888e1dfff8 [General] Allow setting of AI fight & dynamic stats in record packets
Additionally, allow the setting of the Autocalc flag for an NPC record based on an existing record.
2018-08-05 11:00:25 +03:00
Andrei Kortunov
b0f2e00e7f Make forcegreeting a non-op for non-actor objects (bug #4553) 2018-08-05 09:31:45 +04:00
Koncord
d03722b3f4 [Browser] Rework browser for improved stability & clarity
(cherry picked from commits 5c79e7106f, 57353cdfff, 15723adb9a, 01a5196a92, ed75563a94, 3839a2dcfd, 1fd16ba69c, 66283943c5, ba8613a179, 5b8f4f3e92, 35b771b19e, 043eb224e2, 05fac2f67d)
2018-08-05 07:20:12 +03:00
Marc Zinnschlag
452a706047 Merged pull request #1837 2018-08-04 10:26:44 +02:00
Marc Zinnschlag
b6a919a2d1 Merged pull request #1838 2018-08-04 10:26:18 +02:00
Marc Zinnschlag
99c03d55f0 Merged pull request #1841 2018-08-04 10:25:52 +02:00
Marc Zinnschlag
2a621fedd1 Merged pull request #1842 2018-08-04 10:08:11 +02:00
Capostrophic
d15dcaff68
Don't adjust weapon rating according to weapon condition twice 2018-08-03 19:22:58 +03:00
Andrei Kortunov
dd6cb85783 Remove redundant changelog entry 2018-08-03 19:31:10 +04:00
David Cernat
6498bcb22b [Server] Add script functions for getting player draw & sneak states 2018-08-03 18:26:44 +03:00
Andrei Kortunov
e2519226aa Move boost include 2018-08-03 17:04:07 +04:00
Andrei Kortunov
eeffe2e557 Check if item model exists inside drag and drop functions 2018-08-03 16:42:43 +04:00
Andrei Kortunov
e4f862c0b9 Check if next char exists 2018-08-03 16:42:43 +04:00
Andrei Kortunov
c2a175c2e0 Move crash catcher wrapper to separate file 2018-08-03 15:51:17 +04:00
Capostrophic
725a9323c4
Merge branch 'master' into sound 2018-08-03 14:16:51 +03:00
Capostrophic
1d1eedc001
Update changelog 2018-08-03 14:15:58 +03:00
Capostrophic
2f44acafe2
Fix changelog 2018-08-03 14:15:03 +03:00
Capostrophic
4c7f3cf626
Merge branch 'master' into weaponpriority 2018-08-03 14:07:11 +03:00
Capostrophic
433c24562e
Update changelog 2018-08-03 14:06:09 +03:00
Andrei Kortunov
ac98797999 Add missing file 2018-08-03 15:05:13 +04:00
Marc Zinnschlag
4d280add81 Merged pull request #1843 2018-08-03 12:56:17 +02:00
Marc Zinnschlag
d7718aae9b Merged pull request #1840 2018-08-03 12:54:56 +02:00
Marc Zinnschlag
eb5f558f6f Merged pull request #1839 2018-08-03 12:53:55 +02:00
Marc Zinnschlag
79aaf0163a Merged pull request #1833 2018-08-03 12:39:04 +02:00
Andrei Kortunov
712c9995db Rename mIsScripted variable because its name is ambiguous 2018-08-03 12:01:31 +04:00
Andrei Kortunov
c454f1bdad Use log file for editor (feature #4012) 2018-08-03 09:05:08 +04:00
Capostrophic
9d85b7c2d3
Use the actual damage for deducting weapon rating 2018-08-02 15:20:07 +03:00
Capostrophic
73d5496711
Revert addition change 2018-08-02 13:01:23 +03:00
Capostrophic
16af1a6c1c Replace 0 sound range values separately 2018-08-02 12:40:53 +03:00
Capostrophic
3ac030d75a
Handle explicit calls before handling quotes 2018-08-02 09:49:53 +03:00
Capostrophic
80f3bd9f86 Don't apply iWereWolfFleeMod to creatures 2018-08-02 08:36:15 +03:00
Capostrophic
fa6c205e5d Make tab autocompletion work with explicit reference calls 2018-08-02 03:24:31 +03:00
Capostrophic
bec47dfb7c Make ranged weapon bonus a distance-dependent multiplier 2018-08-01 19:57:05 +03:00
Andrei Kortunov
369ea7e177 Check if a temporary file was successfully closed 2018-08-01 20:36:29 +04:00
Capostrophic
382b68a081
Combat AI: take the actual hit chance in account when rating weapon 2018-08-01 19:27:19 +03:00
Andrei Kortunov
12144de8ed Initialize missing variables 2018-08-01 20:18:37 +04:00
Andrei Kortunov
c0bed0fde2 Handle case when index < 0 2018-08-01 20:17:59 +04:00
Andrei Kortunov
770d86f9bd Initialize cubeSize variable for 360 degrees screenshots correctly 2018-08-01 19:36:55 +04:00
Andrei Kortunov
a08048da4e Avoid dereference after null check 2018-08-01 19:30:30 +04:00
Capostrophic
ab29f9e13f Add permanent barter disposition change option (feature #3103) 2018-08-01 17:31:35 +03:00
Marc Zinnschlag
1c13256456 Merged pull request #1829 2018-08-01 16:17:37 +02:00
Marc Zinnschlag
0e75e3816a Merged pull request #1830 2018-08-01 16:16:30 +02:00
Marc Zinnschlag
8812f9ddfa Merged pull request #1831 2018-08-01 16:15:34 +02:00
Marc Zinnschlag
0c507b74bc Merge pull request #1832 2018-08-01 16:13:59 +02:00
Marc Zinnschlag
7c7af1da61 Merged pull request #1834 2018-08-01 15:47:09 +02:00
Marc Zinnschlag
e8139a5cc7 Merged pull request #1835 2018-08-01 15:46:31 +02:00
AnyOldName3
66c241337d
Merge pull request #1836 from OpenMW/water-shader-tabs
Sort out some tabs which snuck into the water shader
2018-08-01 14:08:16 +01:00
AnyOldName3
f717c9e56d
Sort out some tabs which snuck into the water shader 2018-08-01 14:07:02 +01:00
Capostrophic
4d48ede6f1 Add two missing gameplay settings to Advanced tab 2018-08-01 13:36:31 +03:00
Capostrophic
be2e7e9e09 Make casting caster-linked on-self effects no-op (bug #4378) 2018-08-01 02:41:57 +03:00
Andrei Kortunov
5b92910829 Limit difficulty scaling, as mentioned in docs 2018-07-31 21:14:16 +04:00
Marc Zinnschlag
aac580da6b Merged pull request #1828 2018-07-31 11:10:48 +02:00
Marc Zinnschlag
20d4e27f82 Merged pull request #1821 2018-07-31 10:51:32 +02:00
Andrei Kortunov
c07cc0dc40 Reset animation state after weapon unequipping 2018-07-30 22:24:25 +04:00
Andrei Kortunov
469bb29621 Do not try to handle shape controllers as node controllers 2018-07-30 21:45:17 +04:00
Andrei Kortunov
0f2c3ecb17 Rescale player avatar (bug #4539) 2018-07-30 17:41:43 +04:00
David Cernat
8c40010c87 [General] Add missing inventoryBaseId to creatures in RecordDynamic 2018-07-30 10:59:03 +03:00
David Cernat
b57807407a [General] Implement RecordDynamic packet, part 1
Spell, potion, enchantment, creature, NPC, armor, book, clothing, miscellaneous and weapon record data can now be sent in a RecordDynamic packet. Additionally, the packets include data related to associated magical effects (for spells, potions and enchantments), data related to default inventory contents (for creatures and NPCs) and data related to body parts affected (for armor and clothing).

The server now has associated script functions for setting most of the details of the above, with the main exception being individual creature and NPC stats.

Records can either be created entirely from scratch or can use an existing record (set via the baseId variable) as a starting point for their values. In the latter case, only the values that are specifically set override the starting values. Creature and NPC records also have an inventoryBaseId that can be used on top of the baseId to base their inventories on another existing record.

The client's RecordHelper class has been heavily expanded to allow for the above mentioned functionality.

When players create spells, potions and enchantments as part of regular gameplay, they send RecordDynamic packets that provide the server with the complete details of the records that should be created. When they create enchantments, they also provide the server with armor, book, clothing and weapon records corresponding to the items they've enchanted.

This functionality added by this packet was originally supposed to be exclusive to the rewrite, but I've gone ahead and tried to provide it for the pre-rewrite in a way that can mostly be reused for the rewrite.
2018-07-30 10:56:26 +03:00
Capostrophic
c79f96d0d2 Implement ranged crits (feature #3703) 2018-07-29 19:42:44 +03:00
Andrei Kortunov
1d463d129d Finish AiTarget package, if destination is blocked by other actor 2018-07-29 19:41:31 +04:00
Andrei Kortunov
75835c8326 Prevent NPC from chosing farther pathgrid node 2018-07-29 18:18:05 +04:00
Marc Zinnschlag
9e6cba09a6 Merged pull request #1827 2018-07-29 12:52:51 +02:00
Marc Zinnschlag
84de55fb46 Merged puil request #1824 2018-07-29 12:52:01 +02:00
Marc Zinnschlag
78121c1774 Merged pull request #1823 2018-07-29 12:49:50 +02:00
Marc Zinnschlag
3ba9229f47 Merged pull request #1815 2018-07-29 12:48:20 +02:00
Capostrophic
9c8e284ead Fix quick key activation delay code (regression #4536) 2018-07-29 12:52:29 +03:00
Capostrophic
84a871cac7 Actually enable is_pod test 2018-07-28 23:56:42 +03:00
Andrei Kortunov
6d5d0039ec Make sure we apply OT_Murder only once 2018-07-28 20:45:33 +04:00
Andrei Kortunov
bc82dbbd1b Do not try to find missing animated collision shape again and again 2018-07-28 16:49:00 +04:00
Andrei Kortunov
7e0df01c83 Do not optimize animated shapes (bug #3950) 2018-07-28 16:48:57 +04:00
Andrei Kortunov
2d4ec86b8d Provide launcher icons 2018-07-28 13:18:38 +04:00
Marc Zinnschlag
29a1899045 Merged pull request #1819 2018-07-28 11:13:37 +02:00
David Cernat
2dbf3893c0 [General] Compress item refIds in PlayerEquipment packets 2018-07-28 01:50:44 +03:00
David Cernat
2332423527 [Client] Fix extra qualification error in CellRef when compiling w/ GCC 2018-07-27 21:56:45 +03:00
David Cernat
7136329a94 [Client] Add World::updatePtrsWithRefId() method
This makes it possible to "reload" the Ptrs in active cells when changes happen to the ESM record that they are based on. In practice, the old Ptrs are deleted, their RefNums and MpNums are blanked out, and new Ptrs are created that use the same RefNum and MpNum as before.

The above has required me to also add a method called setRefNum() to CellRef to allow setting a RefNum on the fly.

There may be a more elegant implementation available for updatePtrsWithRefIds(), but it requires additional research.
2018-07-27 21:42:08 +03:00
Andrei Kortunov
28a02ac93b Use file selection dialogue result (bug #4524) 2018-07-27 21:25:21 +04:00
Marc Zinnschlag
b7c159e5b6 Merged pull request #1816 2018-07-27 12:09:10 +02:00
Marc Zinnschlag
c508938674 Merged pull request #1817 2018-07-27 12:06:51 +02:00
Marc Zinnschlag
bbb22643e8 Merge remote-tracking branch 'capostrophic/warning' 2018-07-27 12:05:26 +02:00
David Cernat
9497c7f6f2 [Client] Add back mistakenly removed setting of mpNums for spawns 2018-07-27 00:36:05 +03:00
David Cernat
25fcd09780 [Client] Add doesNpcExist() method to RecordHelper 2018-07-26 23:57:42 +03:00
David Cernat
7995466e3c [Client] Check validity of refIds in ObjectSpawn packets
This reverts c7bcf70c32 because it provides a better solution to the problem solved there, while solving another related problem as well.
2018-07-26 23:57:22 +03:00
David Cernat
8d286657d4 [Client] Update messages when unilaterally creating custom objects 2018-07-26 23:32:31 +03:00
Capostrophic
f7887ab05f
Fix MSVC C4456 warning: declaration of 'stats' hides previous local declaration 2018-07-26 23:24:26 +03:00
David Cernat
c7bcf70c32 [Client] Ignore ObjectSpawn packets trying to spawn non-actors 2018-07-26 22:41:04 +03:00
David Cernat
d93b67ef21 [General] Sync soul refIds for items and add related script functions 2018-07-26 22:37:04 +03:00
David Cernat
f52364e05c [Client] Always create new references for new creature disguises
Previously, attempts to reuse the same reference for multiple creature disguises led to movement animation issues, as well as a dynamic_cast error in Creature::getInventoryStore() that made a DedicatedPlayer vanish completely when they first lost their creature disguise, then disguised themselves as a creature that could not hold weapons and then disguised themselves as a creature that could hold weapons.
2018-07-26 21:08:12 +03:00
David Cernat
60bc7447d9 [Client] Rework RecordHelper and add methods for other record types
The usage of const_cast has been replaced with usage of MWWorld::getModifiableStore() and ESMStore::overrideRecord()

Methods whose names started with "update" now start with "override", for consistency with ESMStore's overrideRecord()

New methods have been added for "overriding" enchantment, potion and spell records, which actually leads to them being created with their already set refIds if they haven't been created yet, as per the description of ESMStore::overrideRecord(): "Insert a record with set ID, and allow it to override a pre-existing static record."

Usage of RecordHelper methods has been updated in DedicatedPlayer.
2018-07-26 21:01:59 +03:00
Capostrophic
51d369d4da Add resumeGame method 2018-07-26 20:35:34 +03:00
David Cernat
4e78642273 [Client] Add getModifiableStore() to MWWorld 2018-07-26 20:05:36 +03:00
David Cernat
d778bc3b8a [Server] Turn readWorldstate and writeWorldstate into static variables 2018-07-26 20:03:42 +03:00
David Cernat
c3ff273a22 [General] Add getVectorSize() and resetVector() to Utils 2018-07-26 20:01:58 +03:00
David Cernat
b4802e4201 [General] Use Time struct for time in BaseWorldstate 2018-07-26 19:01:27 +03:00
Andrei Kortunov
23d917df9c Do not use magic numbers in capacity calculations 2018-07-26 18:06:36 +04:00
David Cernat
a4b588d1b5 [General] Add optional timestamps to journal entries in PlayerJournal 2018-07-26 04:36:12 +03:00
Capostrophic
e55f49be45
Fix issue 4494 number 2018-07-25 12:51:15 +03:00
Capostrophic
cac2bc768e
Fix NPC "can't teach more" message (bug #4494) 2018-07-25 12:34:33 +03:00
David Cernat
ea8a41160c [General] Make ActorAttack packet consistent with PlayerAttack
Additionally, fix a typo in PlayerAttack where a boolean argument was outside of the parentheses it should have been in.
2018-07-24 22:43:00 +03:00
David Cernat
b79221efcc [Server] Rename variable i into index in ActorFunctions 2018-07-24 21:29:40 +03:00
David Cernat
8fbed1f808 [General] Remove custom data from PlayerSpellbook packet
It has never made sense to have custom spell data in PlayerSpellbook packets, so it has been removed.
2018-07-24 20:58:55 +03:00
David Cernat
2e0b6e4e3e [Server] Rename variable i into index in script function arguments
Additionally, rename i into index in LangLua.
2018-07-24 20:14:51 +03:00
David Cernat
65de028e0d
Merge pull request #462 from OpenMW/master
Add OpenMW commits up to 23 Jul 2018
2018-07-23 23:19:17 +03:00
David Cernat
74fa1d0f01 [Client] Fix manual setting of inertial force
Actors who are on the ground have their inertial force ignored, so they are now made to not be regarded as being on the ground in World::setInertialForce()
2018-07-23 23:04:41 +03:00
David Cernat
b69e6b96e6 [Client] Use verbose logging level for LocalActor debug 2018-07-23 22:11:59 +03:00
Bret Curtis
84b80ae405 no spaces in assignment 2018-07-22 23:12:37 +00:00
David Cernat
36ac2d9de4 [Client] Set packetOrigin for all ObjectList packets sent 2018-07-23 01:39:43 +03:00
David Cernat
692ee01340 [Client] Add ScriptController w/ contextType-to-packetOrigin method 2018-07-23 00:48:23 +03:00
David Cernat
63a86f145d [Client] Record type of each InterpreterContext for later checking 2018-07-23 00:46:07 +03:00
David Cernat
d4a84ac34a [Server] Update script function descriptions for ObjectList origin 2018-07-22 23:08:32 +03:00
David Cernat
3165c84db4 [General] Rework PACKET_ORIGIN enum
Additionally, comment out reading of originClientScript in ObjectPacket for now.
2018-07-22 22:43:40 +03:00
David Cernat
9e6459043b [General] Fix typo related to originClientScript in ObjectPacket 2018-07-22 20:29:27 +03:00
David Cernat
3dc2d1b214 [General] Add packetOrigin and originClientScript to ObjectList packets
Additionally, add script functions for getting the packetOrigin and originClientScript of received ObjectList packets.
2018-07-22 18:38:05 +03:00
David Cernat
b891acd46e [Client] Send Container packets when items are added/removed via scripts
Additionally, disable unilateral addition and removal of items on clients, and expect the server to reply back with an approved addition or removal.
2018-07-22 17:04:17 +03:00
David Cernat
2189ea1a63 [Client] Clean up sending of Container packets 2018-07-22 16:43:27 +03:00
David Cernat
8c0b75d9f4 [Client] Limit PlayerEquipment packets sent by recharging enchantments 2018-07-22 15:30:40 +03:00
David Cernat
715cac807d [General] Add compareFloats to Utils 2018-07-22 15:23:23 +03:00
David Cernat
cb6c37a26d [General] Replace doubles with floats in BaseStructs and BaseWorldstate 2018-07-22 14:20:20 +03:00
David Cernat
18f8725d33 [Client] Remove tab character that somehow made its way into a comment 2018-07-22 10:29:14 +03:00
Bret Curtis
b910106713 Catch an unbound variable before it happens. 2018-07-22 07:17:34 +00:00
Bret Curtis
c959bdcf32
Merge pull request #1813 from rhtucker/master
Added CSS to drop shadow of figure images
2018-07-22 08:51:30 +02:00
Ryan Tucker
9f2ef1e68a Added CSS to drop shadow of figure images 2018-07-21 13:33:56 -07:00
David Cernat
038757b91a [General] Temporarily revert to original rotation animation sync
I originally added rotation animation sync as part of commit 068a45be87. Unfortunately, it meant the PlayerPosition packets were now twice as large as they had been before, which was less than ideal for such a frequently sent packet, which is why Koncord switched to a more optimized approach in commits 5f30dfd5db and d67db1a9bd.

Recently, there have since been some rotation animation problems in OpenMW, which have broken the way Koncord's approach looks. My original approach still looks somewhat okay, so I'm switching back to it until we can figure out how to reuse it under the current circumstances.
2018-07-21 19:27:36 +03:00
Marc Zinnschlag
8b2b37c270 Merged merge request !28 2018-07-21 17:47:19 +02:00
Marc Zinnschlag
ddd5cbd17c Initialise lock state of newly opened subviews (fixes issue #4520) 2018-07-21 17:38:11 +02:00
David Cernat
3944c8aec6 [Client] Ignore WorldRegionAuthority packets that have an empty region 2018-07-21 18:28:31 +03:00
David Cernat
99e64bdcd7 [Client] Remove unused localWeather variable from Worldstate 2018-07-21 16:25:49 +03:00
David Cernat
cd1fc590a7 [Client] Differentiate itemPtr from actor Ptr in DedicatedPlayer method
This fixes a mistake from 8f7da49152
2018-07-21 16:14:07 +03:00
David Cernat
5466092582 [Client] Reduce log level for actor cell changes 2018-07-21 14:41:48 +03:00
David Cernat
20e0100706 [General] Rework Attack packets and add synchronization for item magic 2018-07-21 14:41:27 +03:00
David Cernat
0f0e8b7c08 [Client] Adjust log levels used for weather and global map 2018-07-21 12:08:31 +03:00
David Cernat
f1315ef30d [Cllient] Differentiate itemPtr from actor Ptr in DedicatedActor methods
2427a4f877 mistakenly used the variable name "ptr" for both the actor and the items in that actor's inventory.
2018-07-21 10:16:51 +03:00
David Cernat
b6324e3532 [Client] Clean up debug for spell usage 2018-07-21 09:41:36 +03:00
David Cernat
826e64b40e [Server] Rename isPlayerExists() into doesPlayerExist() 2018-07-21 07:34:45 +03:00
David Cernat
21d5bb4d4e
Merge pull request #460 from OpenMW/master
Add 0.7.0 commits up to 20 Jul 2018
2018-07-21 05:59:57 +03:00
David Cernat
6c50d4199b Merge branch '0.7.0' of https://github.com/TES3MP/openmw-tes3mp into 0.7.0 2018-07-21 05:21:44 +03:00
David Cernat
421d0e7a99 [Client] Make forceWeather false by default for client-sent weather 2018-07-21 05:21:26 +03:00
David Cernat
892d71ce71 [General] Reimplement weather synchronization to allow soft transitions
Although weather sync was added by Koncord to the rewrite in fd721143e2 in a way that used surprisingly few lines of code, it relied on the server requesting weather states every second from authority players and sending them to non-authority players, while also allowing only very sudden weather transitions across regions, i.e. if there was one player in the Ascadian Isles who had stormy weather, and another player with clear weather in the Bitter Coast Region walked across to the Ascadian Isles, that player was instantly made to have stormy weather with no kind of transition at all.

My approach solves both of those problems. It solves the packet spam by only sending weather updates to the server when weather changes happen or when there are new arrivals to a weather authority's region, and it allows for both sudden weather transitions when players teleport to a region and for soft, gradual transitions when players walk across to a region. It is inspired by my previous actor sync, and uses a WorldRegionAuthority packet to set players as region authorities in a similar way to how ActorAuthority sets players as cell AI authorities. Weather changes are created only by the region authority for a given region, and weather packets are also only sent by that authority.

However, it should be noted that gradual weather transitions are used by default in this implementation. To use sudden weather transitions, the serverside Lua scripts need to forward WorldWeather packets with the forceWeather boolean set to true. That is, however, already handled by our default Lua scripts in situations where it makes sense.
2018-07-21 05:20:26 +03:00
Bret Curtis
4c9e1295e8
Merge pull request #1811 from akortunov/fallfix
Set movement speed to 0 when unconscious
2018-07-20 09:30:45 +02:00
Bret Curtis
a54b779672 Revert "Revert "remove breath/doxygen autodoc""
This reverts commit 038d5a5566.
2018-07-19 23:27:39 +02:00
Andrei Kortunov
8281fd903f Set movement speed to 0 when unconscious (bug #4519) 2018-07-19 20:17:32 +04:00
Bret Curtis
ee3aba149d Force RTD to not build any other types of docs. 2018-07-19 14:34:06 +00:00
Bret Curtis
038d5a5566 Revert "remove breath/doxygen autodoc"
This reverts commit f2fc8351bb.

small fixes
2018-07-19 15:51:29 +02:00
David Cernat
b6db570d9c [Client] Display uniqueIndexes in a less confusing way in console 2018-07-19 11:57:06 +03:00
Bret Curtis
105b172fb5
Merge pull request #1809 from akortunov/enumfix
Sort icons in the DataDisplayDelegate
2018-07-17 23:05:18 +02:00
Andrei Kortunov
5c16ce1d36 Sort icons in the DataDisplayDelegate 2018-07-17 22:49:51 +04:00
Marc Zinnschlag
78a2725169 Merged pull request #1806 2018-07-17 12:42:41 +02:00
Marc Zinnschlag
326a3e61f4 Merged pull request #1807 2018-07-17 12:42:12 +02:00
Marc Zinnschlag
0142525ea2 Merged merge request !26 2018-07-17 12:39:14 +02:00
Marc Zinnschlag
111407c282 Merged merge request !24 2018-07-17 12:26:23 +02:00
Andrei Kortunov
38fa4e0a8a Do not play un-equipping animation when we switch to hand-to-hand 2018-07-17 14:10:04 +04:00
David Cernat
9823a77bf2 [General] Turn PlayerRegionAuthority into WorldRegionAuthority
WorldRegionAuthority is a Worldstate packet.
2018-07-17 09:21:13 +03:00
Miloslav Číž
3ff2740e59 Update CHANGELOG 2018-07-16 20:29:00 +02:00
Koncord
2e227c7af5 [Server] Do not allow to connect with an empty plugin list 2018-07-17 01:08:23 +08:00
Koncord
b5c957c473 [Server] Move PreInit code to preInit method 2018-07-17 00:58:37 +08:00
Koncord
1a9bf253f6 [Server] Simplify getPlayer methods, add isPlayerExists method 2018-07-17 00:29:45 +08:00
Koncord
193034f09c [Documentation] Add copyrigts 2018-07-16 21:07:59 +08:00
Bret Curtis
e7e3dab130
Merge pull request #1804 from akortunov/guifixes
Show magic items count in spells window (feature #4509)
2018-07-16 14:16:35 +02:00
Andrei Kortunov
edd5769022 Show magic items count in spells window (feature #4509) 2018-07-16 14:11:03 +04:00
Bret Curtis
1430b64aaa
Merge pull request #1805 from akortunov/editor_markers
Use editor markers for lights and creatures levelled lists
2018-07-16 12:05:42 +02:00
Andrei Kortunov
30716344f2 Fix possible division by zero in the fatigue calculation (bug #4510) 2018-07-16 13:24:12 +04:00
David Cernat
d5d3c0937f [Client] Adjust log level for actor transfers in CellStore 2018-07-16 03:53:09 +03:00
David Cernat
35fdb833df [Client] Verify integrity of credits file 2018-07-16 03:25:01 +03:00
David Cernat
72d286473b [General] Move credits integrity error message to new ErrorMessages file
Additionally, use correct log level for credit integrity message on server.
2018-07-16 03:21:14 +03:00
David Cernat
0b5cb15f71 [General] Turn GameWeather into WorldWeather, now a WorldstatePacket 2018-07-16 02:20:43 +03:00
David Cernat
646111d998 [General] Use correct credits checksum and move it to Version.hpp 2018-07-16 01:05:56 +03:00
David Cernat
0f36c3ea24 [Server] Verify integrity of credits file 2018-07-15 22:50:16 +03:00
David Cernat
22b2b7a9c6 [General] Add Utils methods for checksums 2018-07-15 22:39:57 +03:00
David Cernat
9445db61b4 [Documentation] Update credits 2018-07-15 20:16:22 +03:00
Andrei Kortunov
6ddf6eb885 Use editor markers for lights and creatures levelled lists 2018-07-15 17:25:18 +04:00
Nikolay Kasyanov
21f198af7a Fix debugger detection on macOS (#4511) 2018-07-15 12:36:01 +02:00
David Cernat
4ac371d292 [Server] Delete duplicate WorldKillCount processor with old filename 2018-07-15 05:49:19 +03:00
David Cernat
3649cf553f [General] Rename PlayerKillCount into WorldKillCount
This should clarify the real meaning of the packet and its associated event.

The event itself has been renamed from OnPlayerKillCount to OnWorldKillCount.
2018-07-15 05:34:59 +03:00
David Cernat
18a2d238ab [Client] Don't pop up dialogue screen when an NPC activates another NPC 2018-07-15 04:36:42 +03:00
David Cernat
4ef2aff11e [Client] Remove "Not implemented" message when activating other player
Serverside scripts can now make lots of different things happen as the result of such activation, which is why the message was no longer current.
2018-07-15 04:16:40 +03:00
David Cernat
f13705e8be [Client] Improve debug for ObjectActivate and ConsoleCommand 2018-07-15 04:09:19 +03:00
David Cernat
6ebe09375f [General] Implement ObjectActivate packet & associated script functions 2018-07-15 03:16:04 +03:00
David Cernat
81b160cae8 [General] Add placeholder for ObjectActivate packet 2018-07-15 01:08:31 +03:00
David Cernat
61da0d2475 [General] Turn PlayerInteraction into PlayerInput 2018-07-15 00:36:07 +03:00
David Cernat
32b6134fad [General] Add placeholder for CellReplace packet 2018-07-15 00:17:13 +03:00
David Cernat
a471f5e452 [General] Turn CellCreate into a Worldstate packet 2018-07-14 23:51:49 +03:00
David Cernat
ae55ee7f0b [General] Add getNumberOfDigits to Utils in components 2018-07-14 23:51:49 +03:00
David Cernat
f410cb90d8
Merge pull request #459 from GrimKriegor/bug/missing-luajit-on-pipeline
[Pipeline] Add missing LuaJIT dependency
2018-07-14 22:38:19 +03:00
David Cernat
98ff44172a
Merge pull request #458 from GrimKriegor/hotfix/crashcatcher-sdl-build-issue
[General] Temporarily disable the new OpenMW crash catcher
2018-07-14 22:37:36 +03:00
Grim Kriegor
2fcde5e8ba [General] Temporarily disable the new OpenMW crash catcher
This new crash catcher is preventing TES3MP from building on GNU/Linux
`components/crashcatcher/crashcatcher.cpp:23:28: fatal error: SDL_messagebox.h: No such file or directory`
Disable it until the developers isolate the issue and patch it
2018-07-14 19:46:47 +01:00
Grim Kriegor
88e4927146 [Pipeline] Add missing LuaJIT dependency 2018-07-14 19:39:19 +01:00
David Cernat
6cb5ac6e63 Merge pull request #457 from OpenMW/master while resolving conflicts
Conflicts:
	CMakeLists.txt
	apps/openmw/engine.cpp
	apps/openmw/main.cpp
	apps/openmw/mwgui/windowmanagerimp.cpp
	apps/openmw/mwmechanics/character.cpp
	components/CMakeLists.txt
2018-07-14 03:57:05 +03:00
David Cernat
6d43c8d63d [Client] Send ActorAI with combat when an NPC's fight is set to 100 2018-07-14 02:55:38 +03:00
David Cernat
743933134d [Client] Simplify sending of ActorAI packets for uninitialized actors 2018-07-14 01:00:27 +03:00
David Cernat
5f4ec1331f [Client] Send ActorAI packet when combat is started via a client script 2018-07-14 00:07:15 +03:00
David Cernat
cc9e294cc0 [Client] Send ActorAI packet for new cell after being followed to it 2018-07-13 22:34:36 +03:00
David Cernat
528bd26a3b [General] Allow followers to follow non-authority players through cells 2018-07-13 21:27:29 +03:00
David Cernat
ab5fd0aef8 [Server] Clean up descriptions for Object script functions 2018-07-13 04:55:05 +03:00
David Cernat
6c1173d598 [Client] Rename searchPtrViaRefIndex into searchPtrViaUniqueIndex 2018-07-13 04:33:54 +03:00
David Cernat
09da24f1ea [General] Rename all instances of refNumIndex into refNum
This creates symmetry with mpNum and should cause less confusion in the future.
2018-07-13 04:12:03 +03:00
David Cernat
20296859ee [Server] Clarify functions used for getting data in Networking 2018-07-13 02:40:24 +03:00
David Cernat
04dd59e638 [Server] Use clearer names for functions used to get last received data
Additionally, rename GetObjectChangesSize() into the less confusing GetObjectListSize()
2018-07-13 02:33:50 +03:00
David Cernat
aeb2e57444 [Server] Bring Actor functions in line with Object functions, part 2
The ActorPacket-sending functions now have sendToOtherVisitors and skipAttachedPlayer arguments, except for the ones for ActorList and ActorAuthority (because such arguments don't make sense for those).
2018-07-13 01:25:43 +03:00
David Cernat
837c5369c0 [Server] Add OnActorAI event and remove autosync for ActorAI packets 2018-07-13 01:05:27 +03:00
David Cernat
8f745df055 [Server] Bring Actor functions in line with Object functions, part 1
The last received ActorList can now be copied into the write-only ActorList that can be sent in packets. Changing the pid of the write-only ActorList can now be done separately from clearing its contents.
2018-07-13 01:04:41 +03:00
David Cernat
f0d4f1bbe5 [Client] Send ActorAI packets when followed by an NPC
The packet is sent regardless of whether we are the cell authority or not, so the server can decide what it wants to do with it.
2018-07-12 23:08:17 +03:00
David Cernat
6316f1e590 [Client] Add ActorList methods for sending ActorAI packets
Additionally, use consistent capitalization for AI-related methods.
2018-07-12 20:48:47 +03:00
David Cernat
0fd8f7660b [Client] Replace LocalActor arg with BaseActor in ActorList functions 2018-07-12 20:15:04 +03:00
Marc Zinnschlag
0bd6078826 Merged pull request #1789 2018-07-12 18:56:59 +02:00
Andrei Kortunov
32bd294a8a Add missing changelog entries 2018-07-12 16:39:46 +04:00
Andrei Kortunov
3d1daaebab Rework manual spellcasting (e.g. via scripts) 2018-07-12 16:24:25 +04:00
David Cernat
bdf2f03c4f [General] Remove unnecessary MapChanges struct from BaseWorldstate 2018-07-12 05:06:31 +03:00
David Cernat
59a56ca35e [Client] Disallow clients from scaling their associated players
Additionally, display messages when trying to scale players.
2018-07-12 03:29:38 +03:00
David Cernat
8ca29dbaac [Client] Fix remaining mistakes in debug for received ActorAI packets 2018-07-11 23:11:37 +03:00
David Cernat
5bb442bbd3 [Server] Add sendToOtherVisitors boolean to SendActorAI()
Additionally, avoid repetition in functions that send Actor packets.
2018-07-11 22:17:00 +03:00
David Cernat
25f7a55495 [Client] Improve debug for received ActorAI packets 2018-07-11 19:54:56 +03:00
David Cernat
ceea65f666 [General] Change pre-rewrite's version to 0.7.0-alpha 2018-07-11 19:35:28 +03:00
Miloslav Číž
4e3bc3e403 Change wave parameters based on weather 2018-07-11 17:03:59 +02:00
Bret Curtis
99e4d49e7c
Merge pull request #1787 from akortunov/profilierfont
Use the DejaVuLGCSansMono.ttf for profiler output
2018-07-11 16:00:34 +02:00
Andrei Kortunov
70b6d4983d Use the DejaVuLGCSansMono.ttf in profilier output 2018-07-11 14:41:49 +04:00
Marc Zinnschlag
2d919ba215 changelog cleanup 2018-07-11 10:10:38 +02:00
Marc Zinnschlag
232be000a2 Updated credits file 2018-07-11 10:09:31 +02:00
Marc Zinnschlag
5080a65910 Merged pull request #1796 2018-07-11 10:08:44 +02:00
Marc Zinnschlag
ee759effce Merged pull request #1798 2018-07-11 10:06:30 +02:00
Marc Zinnschlag
fa96154edd Merged pull request #1803 2018-07-11 10:04:59 +02:00
David Cernat
7a646494ee [General] Point to serverCore.lua instead of server.lua in server config 2018-07-11 02:53:40 +03:00
elsid
686830a6e3
Update changelog 2018-07-10 23:52:51 +03:00
elsid
3f21c49479
Put check for nif file name into separate function 2018-07-10 23:46:06 +03:00
elsid
2599aba196
Fix check whether file name starts with x or X
If path doens't contains / or \, then slashpos will be 0.
Therefore slashpos + 1 = 1 doesn't point to first symbol.

xmesh.nif
 ^
 slashpos + 1
2018-07-10 23:46:06 +03:00
David Cernat
bff6e9e235 [General] Implement ActorAI packet, part 5
Allow repetition for AiWander package to be turned on and off.
2018-07-10 23:18:32 +03:00
Andrei Kortunov
c77c50e92b Make Equip console command to bypass most of restrictions (bug #4460) 2018-07-11 00:06:21 +04:00
Capostrophic
3186edc630
Update changelog 2018-07-10 22:22:20 +03:00
Capostrophic
5cb9dc9d12 Use SpellTurnLeft/TurnRight animation groups 2018-07-10 22:19:56 +03:00
Bret Curtis
b390ce3002
Merge pull request #1776 from akortunov/crossbowfix
Apply weapon reload animations only for upper body
2018-07-10 19:16:23 +02:00
Bret Curtis
df1576fcf5
Merge branch 'master' into crossbowfix 2018-07-10 19:15:37 +02:00
Bret Curtis
fde46f03b3
Merge pull request #1801 from terabyte25/terabyte25-trainingskill
Update trainer skill cap based off modified skill instead of based skill
2018-07-10 16:54:28 +02:00
terrabyte25
76fa8a163d
Update CHANGELOG.md 2018-07-10 17:09:14 +04:00
Andrei Kortunov
1c35e20fcc Use 1h animations as fallback for crossbows 2018-07-10 17:02:51 +04:00
Andrei Kortunov
75dcbea365 Apply weapon reload animations only for upper body 2018-07-10 17:00:48 +04:00
Bret Curtis
3f63e625cf
Merge pull request #1802 from Capostrophic/cmake
Update CMake lists for Windows (task #2490)
2018-07-10 14:34:59 +02:00
Capostrophic
d000f2756e Update disabled warnings 2018-07-10 14:20:26 +03:00
Capostrophic
21403f8920 Update changelog 2018-07-10 14:20:26 +03:00
Capostrophic
7fd66c77e6 Update CMake lists for Windows
Don't use the debug console on Release-mode builds
Disable spammy 4297 and 5032 warnings that are not specific to OpenMW
2018-07-10 14:20:25 +03:00
Bret Curtis
5a1dba6a09
Merge pull request #1800 from akortunov/buildfix
Fix build with MSVC
2018-07-10 13:13:13 +02:00
Andrei Kortunov
c921d1c7e9 Refactor NifStream class (eliminate LNK4221 MSVC warning) 2018-07-10 13:32:52 +04:00
David Cernat
2e31c212c0 [Client] Make any ActorAI packet override an actor's desire to fight 2018-07-10 11:33:07 +03:00
David Cernat
79ee976c95 [Client] Implement ACTIVATE action in DedicatedActor::setAI()
Additionally, clean up usage of CreatureStats in DedicatedActor.
2018-07-10 11:31:51 +03:00
David Cernat
0f30e21312 [Client] Add searchPtrViaRefIndex method to World to easily find objects 2018-07-10 11:30:32 +03:00
Andrei Kortunov
27a5da59ba Fix MSVC warnings C4456 2018-07-10 11:29:39 +04:00
Andrei Kortunov
16a4df25d6 Make void function to do not return value 2018-07-10 09:36:39 +04:00
David Cernat
c984fc0881 [Client] Allow AiActivate to be used with specific Ptrs, not just refIds 2018-07-10 08:21:24 +03:00
David Cernat
00c13ae96c [General] Implement ActorAI packet, part 4
The server can now make actors activate players and objects, at least in theory. In practice, OpenMW''s AiActivate package needs to be worked so it allows specific objects as targets instead of just refIds.
2018-07-10 07:07:37 +03:00
David Cernat
0e13207afe [General] Implement ActorAI packet, part 3
The server can now cancel actor AI, make actors travel to a location, make actors wander, and make actors get escorted by a player or another actor.
2018-07-10 05:07:58 +03:00
David Cernat
5baef09f79 [General] Implement ActorAI packet, part 2
The server can now make actors start combat with players or other actors.
2018-07-10 02:47:52 +03:00
David Cernat
5628f3b977 [Client] Fix debug for DedicatedActor::setAI() 2018-07-10 02:05:10 +03:00
David Cernat
b86155dc11 [Client] Allow AiFollow package to have infinite distance when desired 2018-07-10 01:40:57 +03:00
David Cernat
864c66d1d4 [Client] Make sure hasAiTarget is set correctly for DedicatedActors 2018-07-10 01:35:38 +03:00
David Cernat
26ac29e8b1 [Client] Add disclaimer to save dialog about singleplayer-only saves 2018-07-09 22:55:11 +03:00
David Cernat
4d4bced929 [Client] Allow singleplayer-only saves in main menu during multiplayer 2018-07-09 22:53:18 +03:00
terrabyte25
48296a7452
Update trainingwindow.cpp 2018-07-09 23:13:52 +04:00
Marc Zinnschlag
0bdd8f7d03 Merged merge request !19 2018-07-09 17:43:22 +02:00
Marc Zinnschlag
34c7181afc Merged merge request !21 2018-07-09 17:36:48 +02:00
Alexander Stillich
5abc3bd320 Merge branch 'opencs-crash-handler' of gitlab.com:docwest/openmw into opencs-crash-handler 2018-07-09 16:27:33 +02:00
Alexander Stillich
725cc94210 Renamed cc_install to something less cryptic (crashCatcherInstall) 2018-07-09 16:25:55 +02:00
Alex S
d4d2077174 Fixed changelog entry 2018-07-09 16:25:55 +02:00
Doc West
a6f962156c Updated change log 2018-07-09 16:25:55 +02:00
Doc West
467989cdd5 Moved crashcatcher to a component and also use it in CS
Reworked debugger detection (failed on gdb 7.11), it now uses /proc to detect the debugger
2018-07-09 16:25:55 +02:00
Alexander Stillich
1786211b83 Merge branch 'revert-update-fix' of gitlab.com:docwest/openmw into revert-update-fix 2018-07-09 16:24:41 +02:00
Alexander Stillich
1177e5ac79 Issue a single dataChanged() when the modified column changes 2018-07-09 16:23:50 +02:00
Doc West
d26b5a13ef Fixed comment 2018-07-09 16:23:50 +02:00
Doc West
01b8ce5f70 Notify views of changes in all columns when updating the ColumnId_Modification column 2018-07-09 16:23:50 +02:00
Doc West
4a6457c346 Changed the way the revert command works: it now clones the changed record and uses the new RecordBase::revert() method to restore the previous value
Added Flag_Dialogue_Refresh to var type and var value columns so that sub views update properly
2018-07-09 16:23:50 +02:00
Doc West
4222b44dbb Updated change log 2018-07-09 16:23:50 +02:00
Doc West
143eadb58e Use setData() instead of emtitting dataChanged() which does not work on CI. Also Fixes the remaining issue with subviews not updating due to only the modified flag emitting a change, which prevented the widget mapper from working for updates. 2018-07-09 16:21:53 +02:00
Doc West
4780f1b2bd Notify views of changes of all cells in a row to properly update the row after revert 2018-07-09 16:21:53 +02:00
Alexander Stillich
78a5799911 Issue a single dataChanged() when the modified column changes 2018-07-09 16:05:06 +02:00
Bret Curtis
8834396cdd Merge branch 'patch-1' into 'master'
Update documentationHowTo.rst

See merge request OpenMW/openmw!22
2018-07-09 14:05:05 +00:00
Bret Curtis
13d8fba223
Merge pull request #1797 from Capostrophic/moveobject
Fix double call of addContainerScripts on player in moveObject (bug #4490)
2018-07-09 15:16:04 +02:00
Bret Curtis
7f4320feb0
Merge pull request #1799 from lysol90/patch-1
Updates to the texture modding page
2018-07-09 15:14:43 +02:00
Joakim Berg
ba15d0a848
Fixed spelling error 2018-07-09 10:19:32 +00:00
Capostrophic
d09c327b20 Update changelog 2018-07-09 12:36:19 +03:00
Joakim Berg
efcad5e751
Updates to the texture modding page
There were some errors in the texture modding page about normal maps, so I did a quick change. Please do review if I made some errors, spelling or factual.
2018-07-09 08:58:01 +00:00
Capostrophic
14d3b213a1
Fix double call of addContainerScripts on player in moveObject (fixes #4490) 2018-07-08 23:08:57 +03:00
David Cernat
6ff7fa525e [Client] Disable autosaving when waiting 2018-07-08 23:04:30 +03:00
Bret Curtis
a3a002e008
Merge pull request #1790 from rhtucker/master
Migrating necessary parts of Wiki over to RTD.
2018-07-08 20:59:08 +02:00
Marc Zinnschlag
caad14093e Merged pull request #1795 2018-07-08 11:01:27 +02:00
David Cernat
04ba324290 [Client] Disable clientside disabling and enabling of objects 2018-07-08 03:31:48 +03:00
David Cernat
5043fb4246 [Client] Disable clientside disarming of traps 2018-07-08 02:38:10 +03:00
David Cernat
cbb9817913 [Server] Add missing descriptions for PlayAnimation() and PlaySpeech() 2018-07-08 02:03:33 +03:00
David Cernat
6ba9b1742b [Server] Remove unused default parameters for script functions 2018-07-08 01:05:54 +03:00
David Cernat
acdaf1a282 [Client] Disable clientside deletion of objects through console/scripts
Unfortunately, disabling clientside deletion of summons and items that can be picked up requires extra work on actors and inventories respectively, to avoid buggy situations.
2018-07-08 00:39:07 +03:00
David Cernat
8d9fde810e [Client] Disable clientside scaling of objects 2018-07-08 00:28:31 +03:00
David Cernat
f3892d697b [Client] Disable clientside locking and unlocking of objects 2018-07-08 00:06:01 +03:00
David Cernat
563269d359 [Server] Bring comments up-to-date for packet-sending script functions 2018-07-07 20:16:36 +03:00
David Cernat
2f1ef049d2 [Server] Turn sendToAttachedPlayer into skipAttachedPlayer
Unfortunately, default values set in the C++ code for our script function parameters don't actually seem to work, and they always default to false because they receive a nil value from Lua. As a result, to not break compatibility with previous scripts, I've decided to use a skipAttachedPlayer argument instead so it can default to false while still providing the same benefits that sendToAttachedPlayer provided.
2018-07-07 20:08:59 +03:00
Ryan Tucker
380384ff39 Migrated textures section of wiki. 2018-07-07 10:08:13 -07:00
David Cernat
141e404ed9 [Server] Move server administration functions to ServerFunctions class 2018-07-07 19:40:22 +03:00
David Cernat
c0fde5ae97 [General] Add explanation about 0.0.0.0 to server config file 2018-07-07 19:33:54 +03:00
David Cernat
6041425122 [Server] Move Chat functions to new ChatFunctions class 2018-07-07 19:20:25 +03:00
David Cernat
6a3fbf4e98 [Server] Use consistent arguments for script functions that send packets
Previously, there was a confusing separation between script functions that had a "broadcast" argument and script functions that had a "toOthers" argument.

Those with broadcast sent the packet to all players on the server when broadcast was true. Those with toOthers sent the packet to all players other than the packet's attached player.

The former was based on the pattern of the original SendMessage() script function. The latter more closely resembled RakNet's own broadcast argument as seen here:

https://github.com/TES3MP/CrabNet/blob/master/include/raknet/RakPeer.h#L219

This commit makes it so all sending functions have a sendToOtherPlayers argument that is false by default and a sendToAttachedPlayer that is true by default. This should simultaneously allow sending to be more intuitive, while not breaking previous existing scripts to a significant degree.

Additionally, this commit also reduces some code repetition for all instances of packet-fetching in script functions.
2018-07-07 18:29:31 +03:00
David Cernat
14e4f64296 [Server] Add GetVideoFilename() and SendVideoPlay() script functions 2018-07-07 17:09:57 +03:00
David Cernat
3ed9d89280 [General] Use separate variables for video & music filenames in packets 2018-07-07 14:40:35 +03:00
David Cernat
509882b5f6 [Client] Rework MechanicsHelper::getTarget() to avoid crashes 2018-07-07 11:43:57 +03:00
David Cernat
7f0549fc4f [Server] Remove hardcoded sync for VideoPlay and add OnVideoPlay event 2018-07-06 23:37:57 +03:00
David Cernat
ae8b5a0709 [Server] Remove hardcoded sync for Place, Spawn & other Object packets 2018-07-06 23:36:28 +03:00
David Walley
b5abe6a230 Update documentationHowTo.rst
Add a section, under the provisional name "Baby Steps" to describe a minimal process for editing/contributing. Basically just create an account on GitLab, fork openmw there, then edit the relevant document to create Merge Request
2018-07-06 19:06:32 +00:00
David Cernat
e3e1cfc549 [Client] Add forgotten comparison in crimeTime and deathTime check 2018-07-06 20:49:08 +03:00
Capostrophic
bded697f07
Make Goodbye block using hyperlinks 2018-07-06 19:38:36 +03:00
David Cernat
4eb72eecb1 [Client] Fix crash for invalid CellRefs in MechanicsHelper::getTarget() 2018-07-06 18:39:14 +03:00
Bret Curtis
f4146d0079 Merge branch 'patch-1' into 'master'
Update documentationHowTo.rst - extend to integrate GitLab into PyCharm

See merge request OpenMW/openmw!20
2018-07-06 14:50:12 +00:00
David Cernat
4b30a44816 [Client] Compare crimeTime and deathTime when NPCs forgive player crimes
Previously, all crime witnesses stopped being hostile to a respawning player for as long as the player's diedSinceArrestAttempt was true. That meant that, in an area with no guards to arrest the player, crime witnesses did not enage in combat with the player at all ever again until diedSinceArrestAttempt became false.

This commit makes it so the time of the last crime is recorded for each witness, and that is then compared with the time of the LocalPlayer's last death for a one-time crime forgiveness during that player's current life.

This is essentially a gameplay adjustment for "singleplayer with respawns," and will have to be reworked to make sense for every player in multiplayer, though that requires reworking the crime system as a whole and is thus on hold.
2018-07-06 14:17:54 +03:00
Marc Zinnschlag
d9de8ccb5b Merged pull request #1781 2018-07-06 11:55:45 +02:00
Marc Zinnschlag
dd08194c75 Merged merge request !18 2018-07-06 11:37:15 +02:00
Marc Zinnschlag
7ba512b389 Merged merge request !17 2018-07-06 11:27:35 +02:00
Bret Curtis
94ea9e7dd0
Merge pull request #1793 from Capostrophic/death
Ensure forward-compatibility of death animations of pre-0.43.0 saves (bug #4274)
2018-07-06 10:23:51 +02:00
Alex S
6a2b8f7e85 Fixed changelog entry 2018-07-06 08:14:26 +00:00
David Cernat
c23fc3446f [Client] Avoid sending map tiles for Wilderness cells 2018-07-06 03:54:34 +03:00
David Cernat
17c234d9ca [Client] Use initial values for LocalPlayer and LocalActor killers 2018-07-06 02:07:55 +03:00
David Cernat
3e52857e2b [General] Fix build for client and construction set 2018-07-06 01:10:22 +03:00
David Cernat
97cd3effa7 [Client] Make actor debug consistent with object debug 2018-07-06 00:32:45 +03:00
Doc West
6a78379757 Updated change log 2018-07-05 22:59:29 +02:00
Doc West
03c75794c1 Moved crashcatcher to a component and also use it in CS
Reworked debugger detection (failed on gdb 7.11), it now uses /proc to detect the debugger
2018-07-05 22:55:19 +02:00
Capostrophic
33c462c3c2
Update changelog 2018-07-05 22:56:09 +03:00
Capostrophic
9abfabb065
Ensure forward-compatibility of death animations in old saves (fixes #4274) 2018-07-05 22:49:40 +03:00
David Cernat
b0bd12f9dd Merge branch '0.6.3' of https://github.com/TES3MP/openmw-tes3mp into 0.6.3 2018-07-05 22:28:40 +03:00
David Cernat
c075496748 [General] Replace deathReason in death packets with a killer variable
Add serverside script functions for determining the killers of both players and actors.

Use unsigned ints for script functions returning an object or actor's refNumIndex or mpNum.

Remove updateDeadState() from LocalPlayer and make its code part of updateStatsDynamic() for simplicity.
2018-07-05 22:24:51 +03:00
David Cernat
934e592bdb [Server] Make spacing in CharClass consistent with other categories 2018-07-05 20:27:42 +03:00
David Cernat
e8ce009521 [Server] Use regular int as return value for GetObjectSummonerPid()
Additionally, clarify descriptions of script functions for getting information about summoners.
2018-07-05 20:26:23 +03:00
David Cernat
f02492a593 [General] Temporarily include target names in mwmp::Target
These will be removed once the server can get the names matching refIds by reading content files.
2018-07-05 19:40:28 +03:00
Doc West
b8e53b5b81 Fixed comment 2018-07-05 18:10:43 +02:00
Doc West
e187733811 Notify views of changes in all columns when updating the ColumnId_Modification column 2018-07-05 18:03:55 +02:00
Doc West
f9b565a46e Removed QDebug include, moved updateUndoRedoAction to an anonymous namespace 2018-07-05 17:29:58 +02:00
Doc West
61109d70b1 Removed invalid / unused signal / slot connection 2018-07-05 17:21:32 +02:00
David Cernat
691b332d03 [Client] Use MechanicsHelper::getTarget() for summoners in ObjectList 2018-07-05 16:38:03 +03:00
David Cernat
130a32ebb0 [Client] Add new methods for handling mwmp::Target in MechanicsHelper 2018-07-05 16:36:52 +03:00
Koncord
7a032baaa3 [General] Move OSG hack to ELSE branch 2018-07-05 21:08:41 +08:00
Koncord
533cd9cdec [General] Fix FindRakNet 2018-07-05 19:49:33 +08:00
Koncord
470ea50b54 [General] Use LuaJit instead default Lua 2018-07-05 19:21:53 +08:00
David Walley
9ebcd65634 Update docs/source/reference/documentationHowTo.rst 2018-07-05 10:58:52 +00:00
Bret Curtis
b36bd75b59
Merge pull request #1792 from Capostrophic/character
Make spellcasting stance transition more smooth (bug #4358)
2018-07-05 11:45:31 +02:00
David Walley
d03f9125e3 Update documentationHowTo.rst - extend to integrate GitLab into PyCharm
A subsequent MR will suggest moving most of this to a separate document for intermediate-level contributors, and replacing it with much simpler instructions for beginners - basically edit directly on GitLab as suggested by Psi29a on the forum here - https://forum.openmw.org/viewtopic.php?f=43&p=56458#p56457
2018-07-05 08:45:09 +00:00
David Cernat
32ad8ef2f0 [General] Fix incorrect capitalization in ObjectMove directives 2018-07-05 06:07:10 +03:00
David Cernat
bbb461a5e5 [General] Make sure data in guiMessageBox is compressed 2018-07-05 02:56:32 +03:00
David Cernat
7010575075 [Server] Return -1 in GetObjectSummonerPid() when the player is invalid 2018-07-05 02:05:10 +03:00
Capostrophic
5bc073603e
Update changelog 2018-07-05 01:59:14 +03:00
Capostrophic
faf3e9ba5a Make spellcasting stance transition more smooth (fixes #4358)
If a movement animation was identical to the previous one that was played, restart it from the point the previous animation ended
2018-07-05 01:57:34 +03:00
Doc West
9bfa01c579 Changed the way the revert command works: it now clones the changed record and uses the new RecordBase::revert() method to restore the previous value
Added Flag_Dialogue_Refresh to var type and var value columns so that sub views update properly
2018-07-05 00:37:19 +02:00
David Cernat
76731f5def [Client] Don't remove SummonKeys with actorIds of -1
This prevents summon duplication caused by a SummonKey sometimes being deleted immediately after being created, before the server can send back an ObjectSpawn packet spawning a creature that can be attached to the SummonKey.
2018-07-05 01:11:45 +03:00
Doc West
3cbbbeceb4 Updated change log 2018-07-04 23:25:24 +02:00
Doc West
bf49a3e760 Use setData() instead of emtitting dataChanged() which does not work on CI. Also Fixes the remaining issue with subviews not updating due to only the modified flag emitting a change, which prevented the widget mapper from working for updates. 2018-07-04 23:22:15 +02:00
Doc West
96cf2cbd05 Notify views of changes of all cells in a row to properly update the row after revert 2018-07-04 22:37:10 +02:00
Doc West
1c1b5986e9 Updated change log 2018-07-04 22:05:07 +02:00
Doc West
5d38160239 Updated change log 2018-07-04 22:03:42 +02:00
Doc West
2c39dba83b Updated change log 2018-07-04 22:01:45 +02:00
Doc West
baf21362e1 Fixed undo / redo actions losing their shortcuts 2018-07-04 21:47:16 +02:00
Doc West
414f626309 Implemented search case sensitivity 2018-07-04 21:03:54 +02:00
David Cernat
c2411982d2 [Client] Log object refNumIndexes and mpNums in a consistent way 2018-07-04 21:54:11 +03:00
Bret Curtis
2ff9dc34a4 Merge branch 'win10_ci' into 'master'
see if we can get win10 going

See merge request OpenMW/openmw!8
2018-07-04 16:54:28 +00:00
Bret Curtis
d4d46fc602 Build everything but branches until we can allow VM/CIs to run on forked projects. 2018-07-04 16:51:57 +00:00
Bret Curtis
739c49d59b Merge branch 'master' into 'win10_ci'
# Conflicts:
#   CI/before_script.msvc.sh
2018-07-04 15:21:45 +00:00
AnyOldName3
8c153d116b
Merge pull request #1786 from OpenMW/CI_before_script_msvc_fixes
Update before_script.msvc.sh to add GitLab CI support and update dependency links
2018-07-04 15:44:25 +01:00
David Cernat
7775780ad7 [Cllient] Update multiplayer code for handling quick keys 2018-07-04 05:56:10 +03:00
David Cernat
3438061b55 [Server] Add script function for getting a summoner's pid
Additionally, fix typos in the comments for other script functions relating to summoners.
2018-07-04 04:26:44 +03:00
David Cernat
8a23a96da4 [Client] Update initialization of AiFollow packages in multiplayer code 2018-07-04 04:00:12 +03:00
David Cernat
a236ffc4be Merge pull request #456 from OpenMW/master while resolving conflicts
# Conflicts:
#	.travis.yml
#	README.md
#	apps/openmw/mwgui/quickkeysmenu.cpp
#	apps/openmw/mwmechanics/actors.cpp
#	apps/openmw/mwmechanics/combat.cpp
2018-07-04 01:52:29 +03:00
Koncord
79903c455c [General] Allow different types for vectorContains 2018-07-04 01:31:45 +08:00
Bret Curtis
57e2573593
Update before_script.msvc.sh
check if temp directory exists, error out and warn user about it.
2018-07-03 15:59:51 +02:00
Bret Curtis
70e9d5c0a0 ; it? 2018-07-03 13:53:13 +00:00
Bret Curtis
11030e56c4 detect existing dir 2018-07-03 13:41:06 +00:00
Bret Curtis
4f07ca28a6 Try passing the _real_ windows dir to innoinstaller, then using the linux-like directory for mv. 2018-07-03 13:00:19 +00:00
Bret Curtis
d4c9586bd0 try just converting the \ to a / 2018-07-03 12:53:30 +00:00
Koncord
1f4e6e9114 [General] Add integrity checks to Handshake packet 2018-07-03 18:41:03 +08:00
Koncord
f9ff5f10df [General] Reduce packets size and add integrity checks 2018-07-03 18:41:03 +08:00
Koncord
fa2bf0663e [General] Simplify vectorContains 2018-07-03 18:41:03 +08:00
Marc Zinnschlag
908af3720f Merged pull request #1791 2018-07-03 09:37:51 +02:00
Marc Zinnschlag
47d0321366 updated credits file 2018-07-03 09:09:48 +02:00
Marc Zinnschlag
2a367a0c35 updated changelog 2018-07-03 09:09:05 +02:00
Marc Zinnschlag
e50c3657b3 Merged merge request !16 2018-07-03 09:05:59 +02:00
Marc Zinnschlag
9a88f9147e Merged merge request !15 2018-07-03 08:59:57 +02:00
Doc West
e9cc697b60 Sort EnumDelegate values by name 2018-07-03 00:52:23 +02:00
David Cernat
3aa125ceda [Server] Add script functions for getting a summoner's refId and indexes 2018-07-03 00:54:08 +03:00
Koncord
53346e2663 [Client] Return 0 if effect not found 2018-07-03 03:43:38 +08:00
Koncord
c5c1a160b2 [Client] Comment out an unused variable 2018-07-03 03:35:48 +08:00
Koncord
c69819e0db [General] Change type of refNumIndex & mpNum to unsigned 2018-07-03 03:34:30 +08:00
Koncord
99158beb2e [General] Change effectCount type to unsigned 2018-07-03 03:32:46 +08:00
Koncord
895634cd16 [General] Change type of MpNum to "unsigned int" 2018-07-03 03:25:54 +08:00
Koncord
779f2a564d [General] Change "unsigned long" to uint32_t for cross platform compatibility 2018-07-03 03:04:41 +08:00
Koncord
23684489da [General] Fix clang-tidy warning
Converting integer literal to bool, use bool literal instead
2018-07-03 02:50:21 +08:00
Koncord
7639db02f3 [General] RW functions return true on success 2018-07-03 02:28:20 +08:00
Koncord
45c7c3a0b6 [General] Add integrity checks to PacketPreInit 2018-07-03 02:21:36 +08:00
Koncord
d999cc0d55 [General] Add packetValid flag to packets 2018-07-03 02:06:52 +08:00
Koncord
695fb7d4a7 [General] Reorder RW(string) arguments
Change limit of default max string size to 64 KiB
2018-07-03 01:12:59 +08:00
David Cernat
f9ebe400f7 [Server] Add script function for checking if object's summoner is player 2018-07-02 18:32:42 +03:00
Koncord
d162f6fd3a [General] Explicitly use limitations of the master server 2018-07-02 23:29:07 +08:00
Koncord
a48d5b48ef [General] Add maxSize parameter to RW(std::string)
Minor type changes
2018-07-02 23:19:39 +08:00
Koncord
62877f38b7 [General] Remove Terra support
Use LuaJIT instead.
2018-07-02 23:07:09 +08:00
Koncord
685a80887b Remove Pawn support 2018-07-02 23:00:35 +08:00
Andrei Kortunov
f4330cf057 Editor: limit FPS in 3D preview windows (feature #3641) 2018-07-02 12:20:34 +04:00
Thunderforge
7cbc4eeb49 Adding missing override keywords
Prevents compiler warnings such as this:

```
/Users/Will/CLionProjects/OpenMW/apps/openmw/mwgui/windowbase.hpp:65:22: warning: 'onOpen' overrides a member function but is not marked 'override' [-Winconsistent-missing-override]
        virtual void onOpen();
                     ^
/Users/Will/CLionProjects/OpenMW/apps/openmw/mwgui/windowbase.hpp:38:22: note: overridden virtual function is here
        virtual void onOpen() {}
                     ^
```
2018-07-01 19:17:50 -05:00
David Cernat
bef53749ed [General] Replace BaseObject's hasMaster variable with isSummon
Additionally, add a GetObjectSummonState() script function to the server.
2018-07-02 02:25:06 +03:00
David Cernat
8ce225b1cc [Client] Use the casters of damage-dealing spells as death reasons 2018-07-02 00:42:32 +03:00
Marc Zinnschlag
aa5ddd6b28 Merged merge request livestreamer https://www.twitch.tv/vanguardlx best 2018-07-01 15:25:38 +02:00
Finbar Crago
5d9035c6b2 [Fixes #4482] Missing HandToHand on key quick key 0 (introduced in MR !11 for issue #4480)
because apparently i can't count to ten...
2018-07-01 13:46:23 +10:00
David Cernat
958b220835 [General] Send summon duration to server in ObjectSpawn packets 2018-07-01 00:43:29 +03:00
Marc Zinnschlag
3660d55adf updated credits file 2018-06-30 10:21:10 +02:00
Marc Zinnschlag
362798bd90 updated changelog 2018-06-30 10:20:12 +02:00
Marc Zinnschlag
2ea85d0bb6 Merge remote-tracking branch 'gl_finbar-crago/fix_quickkey_segfalt' 2018-06-30 10:17:05 +02:00
Bret Curtis
af75c1e909
Update before_script.msvc.sh
reverting back to what works
2018-06-30 08:40:21 +02:00
Bret Curtis
dcb2ab80f5
Merge pull request #1788 from Capostrophic/armorcond
Make unarmed creature attacks not affect armor condition (bug #2455)
2018-06-30 08:39:06 +02:00
Bret Curtis
4d60fe5a76 reverting back 2018-06-30 06:10:26 +00:00
Finbar Crago
09c9bd34c3 cleanup more unnecessary struct keywords... 2018-06-30 12:43:50 +10:00
Bret Curtis
b8b07b52f0 try this... 2018-06-29 22:42:12 +00:00
Bret Curtis
4177fd04eb
Update before_script.msvc.sh
Does it blend?
2018-06-29 21:08:42 +02:00
Bret Curtis
209359bbc3 Try this on for size... 2018-06-29 19:07:39 +00:00
Bret Curtis
78a3f95ee4 Update before_script.msvc.sh 2018-06-29 18:03:25 +00:00
Bret Curtis
2bf0d598cf
Update before_script.msvc.sh
Wrap in quites
2018-06-29 20:01:35 +02:00
Capostrophic
6e9c08083d
Add missing empty attacker checks 2018-06-29 20:35:45 +03:00
Capostrophic
bccba24c40 Make unarmed creature attacks not affect armor condition (fixes #2455) 2018-06-29 20:18:28 +03:00
Bret Curtis
9b6ea0e89f # because our CI VMs are not public, MRs can't use them and timeout 2018-06-29 15:15:29 +00:00
Bret Curtis
d3dfe17441 try limiting scope 2018-06-29 15:13:06 +00:00
Finbar Crago
69cd7031e7 Merge branch 'master' into fix_quickkey_segfalt 2018-06-29 23:46:36 +10:00
Finbar Crago
596be205c1 cleanup unnecessary struct keywords... 2018-06-29 23:43:51 +10:00
Bret Curtis
06216aa124 Update .gitlab-ci.yml 2018-06-29 13:36:00 +00:00
Finbar Crago
2722ca50fb fix QuickKeysMenu crash on reopening window after item drop + pickup [see: !11#note_85086570] 2018-06-29 23:32:05 +10:00
Bret Curtis
c474709127
Update before_script.msvc.sh 2018-06-29 15:26:11 +02:00
Bret Curtis
ca0f6fff4a Update before_script.msvc.sh 2018-06-29 13:25:36 +00:00
Bret Curtis
dc48a46e50 Update before_script.msvc.sh 2018-06-29 13:22:07 +00:00
Bret Curtis
a6d6dd5995 updating for the nits 2018-06-29 13:17:19 +00:00
Bret Curtis
8811c7141a
Update before_script.msvc.sh
taking nits into account :)
2018-06-29 15:14:23 +02:00
Marc Zinnschlag
a45d86bdf3 Merge remote-tracking branch 'gl_thunderforge/4479/separate-game-advanced-settings-in-launcher-take-2' 2018-06-29 12:55:55 +02:00
Marc Zinnschlag
f06dd39892 Merge remote-tracking branch 'upstream/master' 2018-06-29 12:52:54 +02:00
Bret Curtis
c2ff30c4d7 correcting from GH/AV feedback, testing on GL. 2018-06-29 09:33:51 +00:00
Bret Curtis
a532aef935
Update before_script.msvc.sh
updating version check and correct indentation, wrap BOOST_SDK in "" to support dirs with spaces.
2018-06-29 11:31:37 +02:00
Bret Curtis
4c0e475092
Update before_script.msvc.sh
Use powershell trick with boost_temp so there is little chance of collision.
2018-06-29 10:16:28 +02:00
Bret Curtis
bccd83c656 Use 1.67 2018-06-29 08:09:41 +00:00
Bret Curtis
bc830a9c45 use boost_temp 2018-06-29 08:00:54 +00:00
Bret Curtis
63bbc77ee7 try using the powershell trick from AnyOldName3 2018-06-29 07:51:45 +00:00
Finbar Crago
7ae388086b Merge branch 'master' into fix_quickkey_segfalt 2018-06-29 12:34:53 +10:00
Thunderforge
72f6b1a693 Separating "Game" Advanced Settings into "Game Mechanics" and "User Interface" 2018-06-28 20:13:18 -05:00
Bret Curtis
3379eafd33 Update before_script.msvc.sh 2018-06-28 20:44:22 +00:00
Bret Curtis
3ceb9116de Give pwd -W a try 2018-06-28 20:28:58 +00:00
Finbar Crago
ed71656ea6 fix updateActivatedQuickKey() crash
keyboard numbers don't start at zero...
2018-06-29 01:58:57 +10:00
Bret Curtis
c4a4111b2e Update before_script.msvc.sh 2018-06-28 15:33:32 +00:00
Bret Curtis
fb6ad9faec try %TMP% ? 2018-06-28 15:23:56 +00:00
Bret Curtis
4ad3d66629 try using just ${TMP} 2018-06-28 14:18:58 +00:00
Bret Curtis
8be52d228e
Update before_script.msvc.sh
small fixes
2018-06-28 15:12:26 +02:00
Finbar Crago
24d5fb09da fix crash on simultaneous key presses 2018-06-28 22:55:02 +10:00
Bret Curtis
60ec340fa3 remove toolset_real, use just toolset, do proper comparison 2018-06-28 12:18:01 +00:00
Bret Curtis
71314f0c3a Use boost 1.67 instead of 1.61 2018-06-28 12:03:52 +00:00
Bret Curtis
46575d8de7
Update before_script.msvc.sh
1.61 -> 1.67
2018-06-28 14:01:41 +02:00
Bret Curtis
660193ae1b
Update before_script.msvc.sh
This has working GL Win10 MSVC updates, should be cross-compatible with appveyor.
2018-06-28 13:59:23 +02:00
Bret Curtis
1c4363eaa6 Using SYSTEMDRIVE because TEMP apparently means something different in bash then to windows cmd. 2018-06-28 11:22:54 +00:00
Bret Curtis
7bf502dd02 Bash it out! 2018-06-28 11:09:27 +00:00
Bret Curtis
1061270ac0 Try using @TEMP@ instead of hard coding it. 2018-06-28 11:05:10 +00:00
Bret Curtis
45d77372a0 with 260 char path fixed, this should work. 2018-06-28 10:41:12 +00:00
Bret Curtis
2d70c94733 gather up everything with 7zip 2018-06-28 09:05:39 +00:00
Bret Curtis
f07d50e5bf
Merge pull request #1785 from akortunov/warnfix
Fix some GCC warnings
2018-06-28 10:33:51 +02:00
Bret Curtis
102266d08d
Merge pull request #1784 from nikolaykasyanov/revert-sdl-get-attribute
Revert "Retrieve SDL window settings instead of using magic numbers"
2018-06-28 10:28:49 +02:00
Bret Curtis
a8adb9374b use quotes 2018-06-28 08:24:34 +00:00
Finbar Crago
d790a27060 Merge branch 'master' into fix_quickkey_segfalt 2018-06-28 18:16:00 +10:00
Bret Curtis
7cd0235fed Try creating a zip and archiving it. 2018-06-28 07:56:40 +00:00
Andrei Kortunov
d9a1de0ec7 Do not use deprecated function 2018-06-28 11:13:32 +04:00
Andrei Kortunov
5455490ad2 Avoid fall-through in spell selection 2018-06-28 11:12:48 +04:00
Finbar Crago
80a3f0a0d4 switch mSelectedIndex/mActivatedIndex int to mSelected/mActivated keyData pointers 2018-06-28 17:02:25 +10:00
Finbar Crago
335e2c5897 add keyData struct + general cleanup 2018-06-28 13:27:08 +10:00
David Cernat
9102df7fde [General] Make WorldCollisionOverride also work with specific refIds
For now, this only makes it possible to enforce collision for specific refIds for placed objects.
2018-06-28 04:53:00 +03:00
David Cernat
c7f10892a9 [General] Add vectorContains util for checking strings in vectors 2018-06-28 04:50:01 +03:00
David Cernat
84af9d9999 [Server] Reorder world map script functions 2018-06-28 03:48:16 +03:00
David Cernat
b81ca18316 [Client] Don't clear container Ptrs when disposing of corpses
The reason for this is that only the server should be determine whether a corpse can be disposed of or not.
2018-06-28 01:45:15 +03:00
Bret Curtis
83e23ee6fd gather up artifacts and use all processors available 2018-06-27 20:45:51 +00:00
Nikolay Kasyanov
5fcb091127 Replace FIXME with a detailed explanation of the issue 2018-06-27 22:40:09 +02:00
Bret Curtis
f17426cbcd give boost 1.67 a spin with msvc 14.1 2018-06-27 20:24:08 +00:00
Nikolay Kasyanov
9c78364c45 Revert "Merge pull request #1771 from Xenkhan/master"
This reverts commit 9667dd051c, reversing
changes made to f52e06fc19.
2018-06-27 22:19:09 +02:00
David Cernat
7ffdb18bf9 [General] Implement ActorDeath packet, part 1
ActorDeath packets are sent for dead actors before their StatsDynamic packets. They contain the actor's deathReason in a manner similar to that of PlayerDeath packets.

A future commit will replace the deathReason with a variable named killer which will be an mwmp::Target.
2018-06-27 21:47:55 +03:00
Bret Curtis
8511f2398a try a set and call? 2018-06-27 16:53:27 +00:00
Bret Curtis
df23e0f857 Try calling it directly 2018-06-27 16:39:45 +00:00
Bret Curtis
bd602847b5 fix broken QT 5.7.0 link 2018-06-27 15:07:53 +00:00
Bret Curtis
59a4251a6a try to extract boost higher up in dir, then move. 2018-06-27 14:36:20 +00:00
Bret Curtis
609d6a1b29 bad syntax 2018-06-27 14:05:05 +00:00
Bret Curtis
b6fc204dd3 be more aggressive about suppressing message boxes 2018-06-27 14:02:30 +00:00
Bret Curtis
f7e1083ba4 get more output from boost 2018-06-27 13:34:37 +00:00
Bret Curtis
da5d7afe22 Update .gitlab-ci.yml 2018-06-27 13:25:23 +00:00
Bret Curtis
6751a7991d Update .gitlab-ci.yml 2018-06-27 12:36:12 +00:00
Bret Curtis
2d5f71e5be Update .gitlab-ci.yml 2018-06-27 12:35:02 +00:00
Bret Curtis
edd22342f2 Update .gitlab-ci.yml 2018-06-27 12:32:18 +00:00
Bret Curtis
218353e452 Update .gitlab-ci.yml 2018-06-27 12:19:03 +00:00
Bret Curtis
0105a48a4f give %% a try 2018-06-27 12:15:29 +00:00
Bret Curtis
6d1a83e667 Update .gitlab-ci.yml 2018-06-27 12:10:09 +00:00
Bret Curtis
51179a2c38 try a wildcard? 2018-06-27 12:01:51 +00:00
Bret Curtis
1fdffd6ef9 see if we can get win10 going 2018-06-27 13:57:51 +02:00
Bret Curtis
87d9a4ff0b Merge branch 'zini_updates' into 'master'
last minute updates from zini

See merge request OpenMW/openmw!7
2018-06-27 11:33:01 +00:00
Marc Zinnschlag
520e65f822 last minute updates from zini 2018-06-27 13:32:08 +02:00
Marc Zinnschlag
5ee731d86f updated roadmap section 2018-06-27 12:33:23 +02:00
Marc Zinnschlag
8bc6c85396 last minute changes (this time for real; forgot to merge in the last update from the private repo) 2018-06-27 12:24:21 +02:00
Bret Curtis
f64d949169
Merge pull request #1780 from akortunov/persistanims
Ignore movement from scripted animations
2018-06-27 12:18:48 +02:00
Marc Zinnschlag
8cda355af6 last minute changes to design doc 2018-06-27 12:14:34 +02:00
Marc Zinnschlag
2afcea3870 added post-1.0 design document 2018-06-27 11:59:40 +02:00
Andrei Kortunov
ec73011617 Clean temporary storage if we assign new AI package (bug #4464) 2018-06-27 12:52:43 +04:00
Andrei Kortunov
ee45f54b53 Refactor AiTemporaryStorage usage 2018-06-27 12:48:34 +04:00
Andrei Kortunov
3c7ab976c3 Ignore movement from scripted animations (bug #4475) 2018-06-27 08:22:45 +04:00
Finbar Crago
cac6d59140 Merge branch 'master' into fix_quickkey_segfalt 2018-06-27 12:58:43 +10:00
Bret Curtis
26615d588e Merge branch 'multi_build' into 'master'
Multi build

See merge request OpenMW/openmw!4
2018-06-26 19:45:49 +00:00
Bret Curtis
4d6ca2c387 preserve dmg artifact 2018-06-26 17:45:20 +00:00
Bret Curtis
9e7731259d what if we try make -j2 package ? 2018-06-26 15:40:06 +00:00
Bret Curtis
cfcd9c3fc6 What happens when we don't make install? 2018-06-26 15:36:53 +00:00
Bret Curtis
dd60b8f179 only delete files inside OpenMW.app dir 2018-06-26 15:18:18 +00:00
Bret Curtis
c1aee49b76 clean up after our previous build. 2018-06-26 15:09:51 +00:00
Bret Curtis
06eb9539bd Let make install do it's thing, it's more reasonable on macos and let's only archive that. 2018-06-26 14:51:55 +00:00
Bret Curtis
e068ee3533 tell unzip to overwrite all files 2018-06-26 14:01:10 +00:00
Bret Curtis
9e2c6d9fe1 actually step into the build directory and build! 2018-06-26 13:57:13 +00:00
Bret Curtis
308d78e3da only download via curl if file on server is different than what is currently cached on VM. 2018-06-26 13:54:37 +00:00
Bret Curtis
ae4cb0c3ee no need for macos_qt_formula since on osx there is no more qt4, just qt5 2018-06-26 13:50:45 +00:00
Finbar Crago
43c9fd4cec check MWWorld::Ptr != NULL for MWGui ItemPtr tooltips 2018-06-26 13:41:53 +10:00
Finbar Crago
186ec8c50f rm ContainerStore/refItem 2018-06-26 13:35:04 +10:00
Marc Zinnschlag
705b2dca0e Merged pull request #1777 2018-06-25 11:58:12 +02:00
Marc Zinnschlag
baeaff2309 Merged pull request #1778 2018-06-25 11:57:45 +02:00
Bret Curtis
a0cae78cb2
Merge pull request #1779 from akortunov/coverity
Fix some code coverity issues
2018-06-25 10:33:07 +02:00
Andrei Kortunov
97d8cc0efe Check if the local was not found, just for sure 2018-06-25 11:21:00 +04:00
Andrei Kortunov
7dff8d8fe2 Check cell for null 2018-06-25 10:26:58 +04:00
Finbar Crago
46c6abcf54 add string vectors for name/id in QuickKeysMenu for item lookups 2018-06-25 16:02:28 +10:00
Andrei Kortunov
441463327c Validate map size 2018-06-25 09:57:40 +04:00
Andrei Kortunov
359e748c28 Initialize some missing fields in constructors 2018-06-25 09:35:42 +04:00
Bret Curtis
d008cd0c46 Update .gitlab-ci.yml 2018-06-24 21:26:53 +00:00
Bret Curtis
87f367ec11 Update .gitlab-ci.yml 2018-06-24 17:52:57 +00:00
Capostrophic
d6a170f848
Update changelog 2018-06-24 14:58:54 +03:00
Capostrophic
ecafcefae9
Fall back to regular head when getVampireHead fails 2018-06-24 14:39:48 +03:00
Bret Curtis
f1158e8129 Update .gitlab-ci.yml 2018-06-23 13:50:58 +00:00
Bret Curtis
55de1c1a72 Update .gitlab-ci.yml 2018-06-23 13:22:20 +00:00
Capostrophic
afbe8f2161
Update changelog 2018-06-23 14:29:15 +03:00
Capostrophic
35b0546737 Consider <p> tag when discarding post-EOL tag text (regression #4473) 2018-06-23 14:27:40 +03:00
Finbar Crago
da4c55d5ad prevent segfalt in QuickKeysMenu when item has been removed from player inventory
added a MWWorld::ContainerStore to hold item copies which are then used to find
real items with findReplacement().

(storing the RefId could be a better solution but would probably leave tooltips broken...)
2018-06-23 17:51:32 +10:00
Bret Curtis
40a9d8ac06 Update .gitlab-ci.yml 2018-06-23 07:19:05 +00:00
Bret Curtis
c2826ca878 Update .gitlab-ci.yml 2018-06-22 16:41:20 +00:00
Bret Curtis
393ec99944 Update .gitlab-ci.yml 2018-06-22 15:29:27 +00:00
Bret Curtis
88555c0463 Update .gitlab-ci.yml 2018-06-22 15:20:38 +00:00
Bret Curtis
601b69b36c Update .gitlab-ci.yml 2018-06-22 15:14:09 +00:00
Bret Curtis
dcba3a1058 Update .gitlab-ci.yml 2018-06-22 15:13:09 +00:00
Bret Curtis
516fc0283b Update .gitlab-ci.yml 2018-06-22 15:07:39 +00:00
Bret Curtis
64cc3b3a6a
Merge pull request #1774 from nikolaykasyanov/ci-macos-1013
[macOS, CI] Build using macOS 10.13 SDK
2018-06-22 10:21:00 +02:00
Bret Curtis
9667dd051c
Merge pull request #1771 from Xenkhan/master
Retrieve SDL window settings instead of using magic numbers
2018-06-21 22:22:42 +02:00
Bret Curtis
a55583a395
Merge branch 'master' into master 2018-06-21 22:22:01 +02:00
Xenkhan
f0acc64544
Update changelog 2018-06-21 15:04:04 -05:00
Marc Zinnschlag
f52e06fc19 Merge branch 'glsl-editorconfig' into 'master'
Update .editorconfig to include GLSL

See merge request OpenMW/openmw!3
2018-06-21 18:29:31 +00:00
AnyOldName3
d1736ad0c8 Update .editorconfig to include GLSL 2018-06-21 14:23:30 +00:00
Xenkhan
405a0caf29
Remove unneeded whitespace 2018-06-20 13:56:00 -05:00
Xenkhan
5a4817c147
Get rid of reinterpret_cast<> 2018-06-20 13:33:59 -05:00
Nikolay Kasyanov
90ccf5b42b [macOS, CI] Build using macOS 10.13 SDK 2018-06-20 19:59:55 +02:00
Marc Zinnschlag
22eb037c18 Merged pull request #1773 2018-06-20 19:08:50 +02:00
Bret Curtis
6655b7e512
Merge pull request #1740 from nikolaykasyanov/software-cursor-decompression
Decompress cursors using SDL software renderer on Mac or if OSG >= 3.5.8 or if OPENMW_DECOMPRESS_TEXTURES is set
2018-06-20 17:19:48 +02:00
Bret Curtis
9cf815505b
formatting 2018-06-20 16:21:23 +02:00
Marc Zinnschlag
4e121a7434 updated credits file 2018-06-20 16:17:47 +02:00
Marc Zinnschlag
c90996f991 Merged merge request !1 2018-06-20 16:16:34 +02:00
Marc Zinnschlag
6315848620 Merged merge request !2 2018-06-20 16:02:54 +02:00
Nikolay Kasyanov
65ec58a669 Move the changelog entry to 0.44.0 2018-06-20 15:43:55 +02:00
Bret Curtis
b619c0de2d
Merge pull request #1772 from akortunov/deathanim
Fast-forward death animation to end if death animation was finished earlier
2018-06-20 13:28:36 +02:00
Andrei Kortunov
c195144b17 Take transformation from first node with given name in file (bug #4469) 2018-06-20 14:24:32 +04:00
Atahualpa
c0fc615cd6 Adds the option to ignore "Base" records when running the verifier. (fixes #4466)
Improves previous commit:
1. Initialise mIgnoreBase boolean member with FALSE.
2. Remove isBaseOnly() function and replace with direct use of Record member.
2018-06-20 11:29:38 +02:00
Bret Curtis
664edc5a39
Merge pull request #1757 from akortunov/musicfix
Handle exception when try to load non-music file
2018-06-20 11:18:50 +02:00
Andrei Kortunov
c9756cee4c Fast-forward death animation to end if death animation was finished earlier (regression #4468) 2018-06-20 12:37:58 +04:00
Bret Curtis
3ebebdf3c1
Merge pull request #1751 from wareya/terrainbleeding
Fix #4452
2018-06-20 10:20:11 +02:00
Bret Curtis
f3923a41c0
Merge pull request #1770 from Capostrophic/open
Make Open spells casted by anything trigger player crime event (bug #4461)
2018-06-20 09:44:45 +02:00
Atahualpa
9d61d76e92 Adds the option to ignore "Base" records when running the verifier. (fixes #4466)
Adds a boolean setting to the user preferences. This setting is locally saved to all OpenMW-CS check stages. When a verification is done, the setting is updated on setup for each check stage. If set to true, the boolean value is then used to skip the verification process for every base record - minus some special cases where, e.g., counters are to be set first.

Related issue:
- Fixes #4466: Editor: Add option to ignore base records when running verifier (https://gitlab.com/OpenMW/openmw/issues/4466)

Tests:
The changes were successfully tested in OpenMW-CS by creating faulty "Base" and "Modified" records for every record type (if possible) and, then, running the verifier with and without the option respectively.
2018-06-20 00:20:03 +02:00
Xenkhan
24ddb66af9
Retrieve SDL window settings instead of using magic numbers 2018-06-19 15:03:30 -05:00
Capostrophic
6c23caadd7 Fix crash when a target in a different cell is (un)locked 2018-06-19 20:43:18 +03:00
Adam Bowen
0d70cb9473 Re-link bugtracker links to Gitlab
* Link "1.0" issues to the "1.0" tag
* Link "report a bug" to the issues page
* Link "known issues" to the "Bug" tag
2018-06-19 15:45:04 +00:00
Capostrophic
0731d79c09
Update changelog 2018-06-19 17:06:31 +03:00
Capostrophic
0c4fa55f16 Make Open spells casted by anything trigger player crime event (fixes #4461) 2018-06-19 17:04:38 +03:00
Marc Zinnschlag
101f0b1579 Merge remote-tracking branch 'upstream/master' 2018-06-19 13:46:03 +02:00
Bret Curtis
975597bac9
Merge pull request #1766 from rhtucker/master
Started migrating installation guide from the wiki.
2018-06-19 13:44:06 +02:00
Bret Curtis
c1eb9042b3
Merge branch 'master' into terrainbleeding 2018-06-19 13:40:14 +02:00
Marc Zinnschlag
7cfb7063c2 Merged pull request #1767 2018-06-19 13:30:10 +02:00
Marc Zinnschlag
7be069fcd2 Merged pull request #1743 2018-06-19 13:29:20 +02:00
Marc Zinnschlag
f275e657f6 Merged pull request #1761 2018-06-19 13:27:56 +02:00
Andrei Kortunov
5fd3ec1035 Implement unlockable locks with 'lock 0' console command 2018-06-19 14:17:33 +04:00
Marc Zinnschlag
a8ad530db9 Merged pull request #1749 2018-06-19 11:33:08 +02:00
Marc Zinnschlag
2a52ade219 Merged pull request #1760 2018-06-19 11:26:41 +02:00
rhtucker
fe86e7ffc7
Fixed inconsistent use of "since" 2018-06-18 12:49:48 -07:00
Bret Curtis
1c7d5c68c5 Update CHANGELOG.md, technically solved by moving from redmine over to gitlab. 2018-06-18 09:07:34 +00:00
Capostrophic
0cf2f6452b Update changelog 2018-06-18 03:27:31 +03:00
Capostrophic
8376c8c68e Allow partial matches in NotCell condition (fixes #4459) 2018-06-18 03:27:31 +03:00
Bret Curtis
e93104a6b3
Merge pull request #1758 from Capostrophic/screenshot
Remove screenshot taken message again
2018-06-17 22:26:00 +02:00
Bret Curtis
70dec71c00
Merge pull request #1763 from akortunov/activatedoor
Forbid actors to use teleporting doors
2018-06-17 10:13:16 +02:00
Bret Curtis
3cc6da1db2
Update door.cpp
typo fix
2018-06-17 10:13:03 +02:00
Bret Curtis
88bf74b2a3
Merge pull request #1765 from akortunov/wanderfix
Fix arguments parsing for AiWander console command
2018-06-17 10:00:57 +02:00
Bret Curtis
3f2dbdc8a8
Merge branch 'master' into wanderfix 2018-06-17 10:00:38 +02:00
Bret Curtis
ecfc5fcd63
Merge pull request #1764 from akortunov/lightfix
Ignore lights without CanCarry flags when NPC selects torch
2018-06-17 08:40:50 +02:00
Ryan Tucker
7e23e6586b Put together most of the informal guide on contributing to documentation. 2018-06-16 17:10:35 -07:00
Ryan Tucker
c5f5984c09 Started migrating installation guide from the wiki.
Fixed a bunch of errors that popped up on my local build.
2018-06-16 14:44:49 -07:00
Andrei Kortunov
f3f7487664 Fix arguments parsing for AiWander console command (bug #4458) 2018-06-16 22:11:10 +04:00
Andrei Kortunov
e08b0d3070 Ignore lights without CanCarry flags when NPC selects torch (bug #4457) 2018-06-16 17:34:49 +04:00
Nikolay Kasyanov
75d79e98b9 Force software decompression if OPENMW_DECOMPRESS_TEXTURES is set 2018-06-16 12:38:16 +02:00
Andrei Kortunov
2a65aaf5ab Forbid actors to use teleporting doors (bug #2562) 2018-06-16 14:21:28 +04:00
Nikolay Kasyanov
359f87ab9f Change imageToSurface to return a unique_ptr to avoid manual surface cleanup 2018-06-16 12:12:32 +02:00
Bret Curtis
3f88aa46d0
Merge pull request #1759 from Thunderforge/refactor-launcher-sdl
Refactor SDL loading in Launcher to fix macOS errors
2018-06-15 12:58:44 +02:00
Andrei Kortunov
9c3da41130 Add murder bounty when a player follower commits murder (bug #2852) 2018-06-15 14:31:09 +04:00
Marc Zinnschlag
5a9e382efe Merged pull request #1421 2018-06-15 12:23:08 +02:00
Thunderforge
506d615acc Moving csignal import from main to graphicspage 2018-06-14 22:16:35 -05:00
Thunderforge
e51bfb46c6 Adding Changelog records 2018-06-14 19:42:40 -05:00
Thunderforge
7615e78e52 Move SDL initialization from main.cpp to graphicspage.cpp 2018-06-14 19:39:24 -05:00
Capostrophic
1abf749f03
Remove screenshot taken message 2018-06-14 22:08:53 +03:00
Andrei Kortunov
2854f6ca83 Handle exception if we try to play non-music file (bug #4416) 2018-06-14 21:32:40 +04:00
Miloslav Číž
2a23b53515 Merge branch 'drummyfish/openmw-toggleborders' 2018-06-14 15:33:08 +02:00
Miloslav Číž
477e1437d2 Resolve conflicts 2018-06-14 15:30:28 +02:00
Andrei Kortunov
49ba00a3ec Add NPC validation to esmstore (bug #2772) 2018-06-14 16:48:16 +04:00
Miloslav Číž
34f8eca7bd Fix indent 2018-06-14 13:43:32 +02:00
Miloslav Číž
31c68c534c Merge branch 'drummyfish/openmw-toggleborders' 2018-06-14 13:23:23 +02:00
Miloslav Číž
24078d4a72 Update CHANGELOG 2018-06-14 13:22:12 +02:00
Miloslav Číž
ab8de9fa14 Set node mask to cell borders 2018-06-14 13:18:37 +02:00
Miloslav Číž
414e6caafe Make tb work with distant terrain 2018-06-14 13:14:38 +02:00
Miloslav Číž
f18d57429e Move cell border management to World 2018-06-14 12:27:22 +02:00
Miloslav Číž
1b8d500c07 Make tb command work again 2018-06-14 12:01:09 +02:00
Miloslav Číž
1fd5ad3e56 Use REAL_SIZE constant 2018-06-14 01:01:22 +02:00
Bret Curtis
ccfc07e7e3
Merge pull request #1548 from drummyfish/screenshot360
360° screenshots
2018-06-13 23:11:06 +02:00
Miloslav Číž
dd00e438fe Merge branch 'screenshot360' of https://github.com/drummyfish/openmw into screenshot360 2018-06-13 21:35:03 +02:00
Miloslav Číž
7178ee3a6e Add FIXME comment 2018-06-13 21:34:43 +02:00
Miloslav Číž
d629c30fdb
Merge branch 'master' into screenshot360 2018-06-13 21:16:28 +02:00
Miloslav Číž
5387e3ba8f Update CHANGELOG 2018-06-13 21:15:22 +02:00
Bret Curtis
60d2678cff
Merge pull request #1755 from akortunov/master
Add missing changelog entries
2018-06-13 20:58:17 +02:00
Andrei Kortunov
e814843cdb Add missing changelog entries 2018-06-13 22:48:09 +04:00
Marc Zinnschlag
2b35c5efd7 Merge remote-tracking branch 'upstream/master' 2018-06-13 18:13:15 +02:00
Marc Zinnschlag
aea481eacb Merged pull request #1753 2018-06-13 18:12:38 +02:00
Marc Zinnschlag
f62df90960 Merged pull request #1572 2018-06-13 18:11:31 +02:00
Marc Zinnschlag
17db4b4db3 Merged pull request 1754 2018-06-13 18:05:59 +02:00
Bret Curtis
48d74a8781 Disable testing for now, not yet necessary. 2018-06-13 15:34:13 +00:00
Bret Curtis
a275972361 Merge branch 'add_pipeline_badge' into 'master'
Update README.md to indicate that our gitlab pipeline is building

See merge request OpenMW/openmw!1734
2018-06-13 14:59:36 +00:00
Andrei Kortunov
61c968d550 Ignore broken items when search for replacement (bug #4453) 2018-06-13 18:39:02 +04:00
Bret Curtis
45957dd707
Merge pull request #1647 from Capostrophic/fatigue
Improve the logic of trading formulae (bug #2222)
2018-06-13 16:21:45 +02:00
Marc Zinnschlag
7ca56ccd29 set search status bar to 'no results' message when search yields no results 2018-06-13 15:48:24 +02:00
Andrei Kortunov
81b78a82e8 AI: try to open doors every AI_REACTION_TIME seconds (bug #4454) 2018-06-13 17:47:32 +04:00
Bret Curtis
9bd940e153 Update README.md to indicate that our gitlab pipeline is building 2018-06-13 13:06:37 +00:00
Marc Zinnschlag
7d2394273e added statusbar to search window (Fixes #3276) 2018-06-13 14:55:03 +02:00
Bret Curtis
032768a505 try to use as many cores as possible 2018-06-13 12:38:03 +00:00
Bret Curtis
3f4d5598a5 Update README.md to be more generic about OpenMW 2018-06-13 11:55:33 +00:00
Bret Curtis
da37585a8e Update .gitlab-ci.yml so that we only build with -j2 2018-06-13 10:15:07 +00:00
Bret Curtis
559754fa76 try this dance again 2018-06-13 09:31:39 +00:00
Bret Curtis
a49649c313 Try to get it to run and build on my docker instance. 2018-06-13 09:29:30 +00:00
Bret Curtis
674925dfb5 Merge branch 'psi29a-master-patch-17094' into 'master'
what does this give us from a CI perspective?

See merge request OpenMW/openmw!1732
2018-06-13 09:19:01 +00:00
Miloslav Číž
dcfbd554bb Remove try catch block 2018-06-13 11:12:46 +02:00
Bret Curtis
2e2be76e3f Update .gitlab-ci.yml 2018-06-13 08:20:31 +00:00
Bret Curtis
3e4dc31e39
Merge branch 'master' into fatigue 2018-06-13 10:04:32 +02:00
Bret Curtis
a747318c90
Merge branch 'master' into terrainbleeding 2018-06-13 09:20:49 +02:00
Marc Zinnschlag
4c4d4672d4 Merged pull request #1752 2018-06-13 09:06:20 +02:00
Marc Zinnschlag
1ba0317905 Merged pull request #1670 2018-06-13 09:02:31 +02:00
Marc Zinnschlag
48711bbdde Merged pull request #1592 2018-06-13 08:58:06 +02:00
Miloslav Číž
c3d7ee5a9e Resolve merge conflicts 2018-06-13 08:22:37 +02:00
Thunderforge
b37f325126 #4324/Updating Changelog.md 2018-06-12 22:20:16 -05:00
Thunderforge
058cfb553c Adding CFBundleIdentifier to OpenMW's Info.plist file for Macs 2018-06-12 22:18:06 -05:00
wareya
bd4badc153 update changelog 2018-06-12 21:05:12 -04:00
wareya
94f695cffc Fix #4452 and remove dead code 2018-06-12 21:04:27 -04:00
Miloslav Číž
db8aaa74d6 Start cell border debug drawing 2018-06-13 01:48:31 +02:00
Bret Curtis
3c933ebaad Update .gitlab-ci.yml 2018-06-12 19:10:15 +00:00
Bret Curtis
cc396f4dfd Update .gitlab-ci.yml 2018-06-12 19:06:59 +00:00
Nikolay Kasyanov
224b94c0ce Decompress cursors using SDL software renderer on Mac or if OSG >= 3.5.8 2018-06-12 20:32:02 +02:00
Andrei Kortunov
9c45cc7e48 Use player reference instead of pointer 2018-06-12 22:05:00 +04:00
Marc Zinnschlag
a3911f52a0 Merged pull request #1750 2018-06-12 19:15:14 +02:00
Marc Zinnschlag
6114cff842 updated credits file 2018-06-12 19:14:32 +02:00
Marc Zinnschlag
97773697a9 Merge remote-tracking branch 'florianjw/precise-rotations' 2018-06-12 19:05:52 +02:00
Capostrophic
1c8a20a54a Set ok button focus in settings window by default (fixes #4368) 2018-06-12 19:45:43 +03:00
Marc Zinnschlag
565922f9ad naked expressions beginning with the member operator were allowed erroneously outside of the console (Fixes issue #2971) 2018-06-12 17:52:16 +02:00
Marc Zinnschlag
296ad8424e updated changelog 2018-06-12 17:06:09 +02:00
Marc Zinnschlag
8d0f717e72 Merged pull request #1739 2018-06-12 17:04:41 +02:00
Marc Zinnschlag
90febde783 Merged pull request #1742 2018-06-12 17:03:38 +02:00
Marc Zinnschlag
816a1733dc Allow comma after Begin and End script instruction (Fixes #4451) 2018-06-12 15:29:28 +02:00
Bret Curtis
1c736ea064 Update .gitlab-ci.yml 2018-06-12 12:46:19 +00:00
Andrei Kortunov
bce6d79ad3 Add changelog entries, related to animations 2018-06-12 16:19:28 +04:00
Andrei Kortunov
f299be8158 Play scripted animations even if SkipAnim is used 2018-06-12 16:07:36 +04:00
Bret Curtis
a166534226 Update .gitlab-ci.yml 2018-06-12 11:41:19 +00:00
Bret Curtis
dddceba8f2 Update .gitlab-ci.yml 2018-06-12 11:32:37 +00:00
Bret Curtis
e3832cd2e2 Update .gitlab-ci.yml 2018-06-12 11:24:27 +00:00
Bret Curtis
bc0eb3349b Update .gitlab-ci.yml 2018-06-12 10:33:35 +00:00
Andrei Kortunov
25bb7c1826 Make 'PlayGroup idle' to cancel scripted animations 2018-06-12 14:04:03 +04:00
Bret Curtis
e5dff83e38 Update .gitlab-ci.yml 2018-06-12 09:26:42 +00:00
Bret Curtis
a89441e879 Update .gitlab-ci.yml 2018-06-12 09:26:10 +00:00
Bret Curtis
20d8a424d6 Update .gitlab-ci.yml 2018-06-12 09:09:37 +00:00
Andrei Kortunov
0e441d48ac Give scripted animations highest priority (bug #4286) 2018-06-12 12:55:28 +04:00
Bret Curtis
8c4731728c Update .gitlab-ci.yml 2018-06-12 08:41:07 +00:00
Bret Curtis
de1cad86ab Update .gitlab-ci.yml 2018-06-12 08:37:26 +00:00
Bret Curtis
d986354d53 Update .gitlab-ci.yml 2018-06-12 08:30:18 +00:00
Bret Curtis
8714f48ce7 Update .gitlab-ci.yml 2018-06-12 08:22:44 +00:00
Bret Curtis
04dc74a1d6 Update .gitlab-ci.yml 2018-06-12 08:05:30 +00:00
Marc Zinnschlag
3af003d36b Merge branch 'test_update_workflow' into 'master'
Update README.md with an important distinction.

See merge request OpenMW/openmw!1731
2018-06-12 07:57:55 +00:00
Bret Curtis
7502a7dc4d what does this give us from a CI perspective? 2018-06-12 07:52:53 +00:00
Andrei Kortunov
0c92655250 Avoid code duplication in character manager 2018-06-12 11:51:54 +04:00
Andrei Kortunov
e3812f4075 Check creature stats only for actors 2018-06-12 11:27:18 +04:00
Andrei Kortunov
b0a140e714 Disable actor collision only after end of death animation 2018-06-12 10:00:38 +04:00
Andrei Kortunov
ebaa6fb5a2 Play death scream only once 2018-06-12 09:55:43 +04:00
Bret Curtis
5fba1c599b Update README.md with an important distinction. 2018-06-12 05:52:19 +00:00
Andrei Kortunov
0d3f535590 Warn about mod conflicts 2018-06-12 08:57:24 +04:00
Andrei Kortunov
427be928d0 Do not update animation state for dead actors 2018-06-11 23:17:54 +04:00
Andrei Kortunov
977a27ecb7 Do not clear corpses until end of death animation (bug #4307) 2018-06-11 22:29:32 +04:00
Bret Curtis
7310e3c8c2
Merge pull request #1748 from akortunov/bookfix
Do not show any book text after last <BR> tag
2018-06-11 17:08:26 +02:00
Andrei Kortunov
a42c663fd7 Do not interrupt scripted animations by death animation (bug #4286) 2018-06-11 18:53:25 +04:00
Andrei Kortunov
d0619cfb35 Play death animation for non-persisting actors with 0 health (bug #4291) 2018-06-11 18:52:20 +04:00
Andrei Kortunov
6099735c60 Early out only when scripted animation is playing 2018-06-11 17:52:58 +04:00
Bret Curtis
e53fb953bc
Merge pull request #1746 from Capostrophic/interrupt
Make WakeUpPC interrupt waiting if it was supposed to be (bug #3629)
2018-06-11 15:20:36 +02:00
Andrei Kortunov
e234dd2a36 Do not interrupt scripted animations 2018-06-11 17:18:51 +04:00
Bret Curtis
23d16dc870
Merge pull request #1745 from Thunderforge/patch-1
Adding Feature #4345 to Changelog.md
2018-06-11 09:29:43 +02:00
Andrei Kortunov
66a46ff03c Do not show any book text after last <BR> tag. 2018-06-11 11:22:56 +04:00
Capostrophic
d43766d3c9 Make WakeUpPC interrupt waiting if it was supposed to be (fixes #3629) 2018-06-10 18:42:18 +03:00
Thunderforge
ab03d238bb
Adding Feature #4345
Implemented as part of #1623, but not added.
2018-06-10 07:43:38 -05:00
Andrei Kortunov
acd3cba5fa Store previous items in the savegame 2018-06-10 16:21:19 +04:00
Andrei Kortunov
9fd2d57b86 Move previous items to player 2018-06-10 16:21:19 +04:00
Andrei Kortunov
f977c6876f Bound items: store item ID instead of pointer 2018-06-10 16:21:19 +04:00
Andrei Kortunov
4de9d9fa77 Split adjustBoundItem() 2018-06-10 16:21:19 +04:00
Andrei Kortunov
d1b1cb748d Reequip previous item only if the expired bound item was equipped 2018-06-10 16:21:19 +04:00
Andrei Kortunov
9b72a6ac69 Use the MWWorld::Ptr() instead of string ID 2018-06-10 16:21:19 +04:00
Andrei Kortunov
0375bedab2 Equip previous item after a bound item expires (bug #2326) 2018-06-10 16:21:19 +04:00
Bret Curtis
926ddcd47e
Merge pull request #1741 from akortunov/master
Do not reset mUpperBodyState for weapon->weapon switch
2018-06-10 11:56:54 +02:00
Marc Zinnschlag
dbc87e7c7d updated changelog 2018-06-10 11:28:22 +02:00
Marc Zinnschlag
25e4c52adf Merged pull request #1744 2018-06-10 11:26:54 +02:00
Thunderforge
a9ca528fb8 Adding version number of macOS build of OpenMW 2018-06-09 19:42:24 -05:00
wareya
7344323b9e remove indentation from blank lines 2018-06-09 10:31:51 -04:00
wareya
8f45b0d53a remove unnecessary conditions 2018-06-09 10:11:43 -04:00
Andrei Kortunov
fba0c155df Fix assertion fail related to NiLookAtController 2018-06-09 17:07:38 +04:00
Andrei Kortunov
ae87e0d3fc Do not reset mUpperBodyState for weapon->weapon switch (regression #4446) 2018-06-09 15:34:08 +04:00
Andrei Kortunov
5ead6353ac Add missing changelog entry 2018-06-09 13:10:44 +04:00
Andrei Kortunov
4ba361fea6 Unhardcode sunset and sunrise settings (bug #1990) 2018-06-09 13:09:17 +04:00
Marc Zinnschlag
7d9de93fd3 Merged pull request #1477 2018-06-09 10:52:35 +02:00
Marc Zinnschlag
551a69f1b1 Merged pull request #1559 2018-06-09 10:51:02 +02:00
Marc Zinnschlag
efb4abbb7f Merged pull request #1623 2018-06-09 10:49:04 +02:00
Marc Zinnschlag
619110ca4c Merged pull request #1737 2018-06-09 10:47:54 +02:00
Marc Zinnschlag
76972bb2f6 Merged pull request #1709 2018-06-09 10:46:02 +02:00
Marc Zinnschlag
6a4cd975b6 Merge remote-tracking branch 'capostrophic/goodbye' 2018-06-09 10:44:14 +02:00
Thunderforge
dfa9968565 Renaming Launcher::DataFilesPage::signalSelectedFilesChanged to signalLoadedCellsChanged 2018-06-08 19:18:23 -05:00
Thunderforge
62c4eb8d6a Explicitly flagging loaded cells changed as queued 2018-06-08 19:16:24 -05:00
wareya
6277f5511c fix #3876 and #3993 2018-06-08 17:52:46 -04:00
Andrei Kortunov
2e6cf2a414 Add changelog entries 2018-06-08 21:54:24 +04:00
Andrei Kortunov
6ed2773299 Do not stack return packages 2018-06-08 21:53:47 +04:00
Andrei Kortunov
74a2cbe696 AI: return back after pursuit 2018-06-08 21:53:47 +04:00
Andrei Kortunov
3d0631cfcc Store last AI package in savegame 2018-06-08 21:53:47 +04:00
Andrei Kortunov
3a0ee78d2b AiTravel: store mHidden flag in savegame 2018-06-08 21:53:47 +04:00
Andrei Kortunov
2f5beb8853 Remove unnecessary hack 2018-06-08 21:53:47 +04:00
Andrei Kortunov
57d686131e Remove redundant condition 2018-06-08 21:53:47 +04:00
Andrei Kortunov
5105c67642 Add mHidden field to AiTravel 2018-06-08 21:53:47 +04:00
Andrei Kortunov
81f29d8dcd AiWander: resume moving to destination after combat 2018-06-08 21:53:47 +04:00
Andrei Kortunov
18ff097e4a Add the parameter to AiSequence::stack() to control ability to cancel other AI packages 2018-06-08 21:53:47 +04:00
Andrei Kortunov
9d27eb197f AiWander: return to initial position only after combat 2018-06-08 21:53:47 +04:00
Bret Curtis
3c2c0960d1
Merge pull request #1734 from MocquillonCedric/windows-cmake-pre3.9-support
Add support for msvc with cmake version pre 3.9 (fixes #4429)
2018-06-08 19:14:01 +02:00
Bret Curtis
61c969e970
Merge branch 'master' into hitboxfix 2018-06-08 18:36:44 +02:00
Capostrophic
b274931165
Revert erroneous changes 2018-06-08 19:18:53 +03:00
Capostrophic
dd2a11b243
Merge branch 'master' into goodbye 2018-06-08 19:16:36 +03:00
Capostrophic
99781ab70c
Fix changelog 2018-06-08 19:15:31 +03:00
Capostrophic
01f12a6bd5
Update changelog 2018-06-08 19:01:48 +03:00
Capostrophic
24c1ee7744 Use relative stat difference for haggling 2018-06-08 19:00:45 +03:00
Capostrophic
b7026df551 Improve the offered price formula (Fixes #2222) 2018-06-08 19:00:45 +03:00
Andrei Kortunov
fed10e87aa Store integer actor ID in AI packages (bug #4036) 2018-06-08 19:57:41 +04:00
Marc Zinnschlag
9d0ce25052 Merged pull request #1738 2018-06-08 17:28:08 +02:00
Cédric
de5a3eaae9 Fix indentation issue: replace tab by spaces 2018-06-08 17:08:44 +02:00
Marc Zinnschlag
7899f44173 Merged pull request #1619 2018-06-08 17:07:38 +02:00
Bret Curtis
6c04cecab1
Merge pull request #1704 from akortunov/per_group_animation
[Feedback needed] Support for per-group KF-animation files
2018-06-08 15:06:43 +02:00
Andrei Kortunov
fea34bd73f Added support for per-group animation files 2018-06-08 17:04:15 +04:00
Capostrophic
0db702dfa7
Update changelog 2018-06-08 15:05:00 +03:00
Capostrophic
11103211c5 Make Goodbye and Choice choices mutually exclusive 2018-06-08 15:03:19 +03:00
Andrei Kortunov
2fada94879 Improve MRK NiStringExtraData handling (bug #4419) 2018-06-08 15:44:35 +04:00
Marc Zinnschlag
53e8882366 updated changelog 2018-06-08 11:44:49 +02:00
Marc Zinnschlag
21ea49fe83 Merge remote-tracking branch 'capostrophic/physics' 2018-06-08 11:43:10 +02:00
Cédric
b784c7873d Update authors 2018-06-08 06:36:43 +02:00
Cédric
4a9b790dbe Update changelog 2018-06-08 06:36:11 +02:00
Cédric
7cafec9861 Add support for msvc with cmake version pre 3.9 (fixes #4429) 2018-06-08 06:34:40 +02:00
Capostrophic
1a354f88ac Make choices trigger goodbye if Goodbye is used (fixes #3897) 2018-06-07 22:09:55 +03:00
Andrei Kortunov
05026b891e Add changelog entries 2018-06-07 20:42:18 +04:00
Andrei Kortunov
6eb531c6ac Add missing changelog entries 2018-06-07 16:22:52 +04:00
Andrei Kortunov
1b9edbe119 Add unequip animation during stance switching (bug #4327) 2018-06-07 16:20:17 +04:00
Andrei Kortunov
bde1d07d4e Use hitboxes and focused object for touch spells (bug #3374) 2018-06-07 16:12:27 +04:00
Andrei Kortunov
4666a6a0ab Use default hit formula as fallback 2018-06-07 16:12:27 +04:00
Andrei Kortunov
9e5d577a71 Aim from center of attacker to center of target 2018-06-07 16:12:27 +04:00
Andrei Kortunov
f5dc9f0162 Use hitbox cone only as fallback 2018-06-07 16:12:27 +04:00
Andrei Kortunov
ab433102a4 Increase hit distance for player by halfExtents 2018-06-07 16:12:27 +04:00
Thunderforge
d46590934a Importing mutex 2018-06-03 16:59:27 -05:00
Thunderforge
e282ece3d1 Fixing bug with autocomplete not loading correctly during startup 2018-06-03 16:58:18 -05:00
Thunderforge
103a7ac628 Using a mutex lock to prevent race conditions 2018-06-03 16:32:12 -05:00
Thunderforge
e26c675829 Changing join to detach so that the thread will not block the UI 2018-06-02 17:29:35 -05:00
Thunderforge
26dfef7970 Changing where we are loading cells to prevent Qt access issue 2018-05-27 17:15:36 -05:00
Thunderforge
78234e9468 Moving autocomplete code to thread 2018-05-27 16:47:09 -05:00
Thunderforge
c2fff61ccd Changing so that data changes happen only after the addon is checked 2018-05-26 20:35:28 -05:00
Thunderforge
d58cce9c72 Adding WIP code to dynamically change the autocomplete fields 2018-05-22 20:50:31 -05:00
Capostrophic
e32f38b939 Allow jumping when you're stuck on a slope (fixes #4221) 2018-05-13 17:19:33 +03:00
Thunderforge
fb27f34a32 Add autocomplete to the "Start default character at" field 2018-04-07 21:27:36 -05:00
Thunderforge
d42791e260 Moving testing options to Advanced page 2018-03-15 22:11:54 -05:00
Thunderforge
f07a12af73 Changing label "and may cause issues" to "and will cause issues" 2018-03-08 18:09:18 -06:00
Thunderforge
6931f6cadc Adding message indicating the purpose of the "Testing" block 2018-03-07 18:37:43 -06:00
Thunderforge
dcc262ed91 Fixing Skip Menu checkbox not working correctly 2018-03-05 23:10:08 -06:00
Thunderforge
082e166fae Making "start default character at" field enabled or disabled by the previous checkbox 2018-03-05 21:41:29 -06:00
Thunderforge
da74ca5ce0 Add testing options to the Settings page 2018-03-05 21:26:59 -06:00
Florian Weber
10fe334247
add more precise float-spinbox and use it for rotations 2018-03-02 15:05:00 +01:00
Miloslav Číž
db6107f12f
Merge branch 'master' into screenshot360 2018-02-25 11:25:19 +01:00
Miloslav Číž
a142a67972 Add default settings for 360 screenshots 2017-12-06 21:16:30 +01:00
Miloslav Číž
37aa761283 Change spherical screenshot filtering to nearest 2017-12-01 21:47:26 +01:00
Miloslav Číž
390838e084 Replace switch with ifs in shader 2017-12-01 21:03:29 +01:00
Miloslav Číž
ea5e078526 Update shaders in CMakeLists 2017-12-01 19:54:48 +01:00
Miloslav Číž
df61a30259 preincrement 2017-11-16 23:20:24 +01:00
Miloslav Číž
ddbf6c162f use linear filtering for the cubemap 2017-11-16 22:43:41 +01:00
Miloslav Číž
fc507c66f7 remove no longer needed stuff 2017-11-16 22:17:00 +01:00
Miloslav Číž
3ae5310567 use loading screen to freeze the screen 2017-11-16 22:08:33 +01:00
Miloslav Číž
2b5f147545 allow non-power-of-2 sized cubemaps 2017-11-16 20:06:34 +01:00
Miloslav Číž
902862aa8b display confirming message for all screenshots 2017-11-16 13:50:10 +01:00
Miloslav Číž
bccff768ff select closest power of 2 resolution for the cubemap 2017-11-16 13:41:09 +01:00
Miloslav Číž
56c74fb96f add scene switch node 2017-11-16 12:46:46 +01:00
Miloslav Číž
1a4f351e3d move camera freeze code 2017-11-16 12:17:52 +01:00
Miloslav Číž
af38d3a47d get rid of sphericalscreenshot class 2017-11-15 17:01:16 +01:00
Miloslav Číž
226fb9c26b render cubemaps in OGL coordinates 2017-11-15 16:07:01 +01:00
Miloslav Číž
1c3d45f641 dirty 360 screenshot GPU setup 2017-11-15 15:20:59 +01:00
Miloslav Číž
823218bb61 freeze screen during screenshot taking 2017-11-14 18:23:12 +01:00
Miloslav Číž
1ab854446c remove unused include 2017-11-11 17:21:01 +01:00
Miloslav Číž
511a5686da planet mapping adjustment 2017-11-11 15:10:54 +01:00
Miloslav Číž
4fc532d873 reference screenshot settings only from one place 2017-11-11 14:32:28 +01:00
Miloslav Číž
d71d984cfa more unused stuff cleanup 2017-11-11 14:14:24 +01:00
Miloslav Číž
e804c4a011 remove no longer used method 2017-11-11 13:54:14 +01:00
Miloslav Číž
525f8b4d8e get rid of special key for 360 screenshot 2017-11-11 13:51:42 +01:00
Miloslav Číž
1f49612ca3 enable water effects for 360 screenshots 2017-11-10 19:18:16 +01:00
Miloslav Číž
319ed2f9b8 disable 360 screenshots in vanity/preview mode 2017-11-10 15:23:44 +01:00
Miloslav Číž
497b33e403 small corrections 2017-11-10 14:28:09 +01:00
Miloslav Číž
9ab3a0c44b set cubemap width differently 2017-11-10 11:16:25 +01:00
Miloslav Číž
5baff05bac add cubemap mapping 2017-11-10 10:50:28 +01:00
Miloslav Číž
5a07d135ae add settings for cubemap size 2017-11-10 10:34:46 +01:00
Miloslav Číž
43c49e2f31 delete accidentally commited files 2017-11-09 23:12:23 +01:00
Miloslav Číž
1b184d8716 correct player mask 2017-11-09 23:09:13 +01:00
Miloslav Číž
e54c0a90fa fix mirrored spherical screenshots 2017-11-09 21:14:02 +01:00
Miloslav Číž
d763e9fe46 add settings for spherical screenshots 2017-11-09 20:25:29 +01:00
Miloslav Číž
8f32114025 segfault fix 2017-11-09 18:26:27 +01:00
Miloslav Číž
d4fd08a63f save 360 screenshots in the configured directory 2017-11-09 16:49:46 +01:00
Miloslav Číž
1b97a541f4 make a new action for 360 screenshot 2017-11-09 16:06:29 +01:00
Miloslav Číž
f60840754f disable water effects for spherical screenshots 2017-11-09 14:44:42 +01:00
Miloslav Číž
5698d70806 small planet mapping 2017-11-08 12:58:27 +01:00
Miloslav Číž
5f36518181 spherical mapping 2017-11-08 09:15:45 +01:00
Miloslav Číž
4761a3d98b dirty cylindrical projection 2017-11-07 22:13:05 +01:00
Miloslav Číž
3be9e2ee95 make spherical screenshot class 2017-11-07 19:47:36 +01:00
Miloslav Číž
5afe02505b hide player in first person 360 screenshot 2017-11-07 16:12:31 +01:00
Miloslav Číž
ce55d7c2f5 basic cubemap rendering 2017-11-07 15:02:01 +01:00
Miloslav Číž
7feba7e498 basic setup for 360 screenshots 2017-11-07 13:07:11 +01:00
945 changed files with 40618 additions and 17501 deletions

View file

@ -9,3 +9,8 @@ insert_final_newline = true
indent_style = space
indent_size = 4
insert_final_newline = true
[*.glsl]
indent_style = space
indent_size = 4
insert_final_newline = false

69
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,69 @@
stages:
- build
Debian:
tags:
- docker
- linux
image: gcc
cache:
key: apt-cache
paths:
- apt-cache/
before_script:
- export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
- apt-get update -yq
- apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev
# - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old
- curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb
- curl http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb
- curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb
- curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb
- curl http://ftp.us.debian.org/debian/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb
- dpkg --ignore-depends=libmygui.ogreplatform0debian1v5 -i *.deb
stage: build
script:
- cores_to_use=$((`nproc`-2)); if (( $cores_to_use < 1 )); then cores_to_use=1; fi
- mkdir build; cd build; cmake -DCMAKE_BUILD_TYPE=MinSizeRel ../
- make -j$cores_to_use
- DESTDIR=artifacts make install
artifacts:
paths:
- build/artifacts/
MacOS:
tags:
- macos
- xcode
except:
- branches # because our CI VMs are not public, MRs can't use them and timeout
stage: build
allow_failure: true
script:
- rm -fr build/* # remove anything in the build directory
- CI/before_install.osx.sh
- CI/before_script.osx.sh
- cd build; make -j2 package
artifacts:
paths:
- build/OpenMW-*.dmg
Windows:
tags:
- win10
- msvc2017
except:
- branches # because our CI VMs are not public, MRs can't use them and timeout
stage: build
allow_failure: true
script:
# - env # turn on for debugging
- sh %CI_PROJECT_DIR%/CI/before_script.msvc.sh -c Release -p x64 -v 2017 -V
- SET msBuildLocation="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe"
- call %msBuildLocation% MSVC2017_64\OpenMW.sln /t:Build /p:Configuration=Release /m:%NUMBER_OF_PROCESSORS%
- 7z a OpenMW_MSVC2017_64_%CI_BUILD_REF_NAME%_%CI_BUILD_ID%.zip %CI_PROJECT_DIR%\MSVC2017_64\Release\
cache:
paths:
- deps
artifacts:
paths:
- "*.zip"

3
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "extern/breakpad"]
path = extern/breakpad
url = https://chromium.googlesource.com/breakpad/breakpad
[submodule "extern/sol"]
path = extern/sol
url = https://github.com/ThePhD/sol2

View file

@ -1,6 +1,10 @@
os:
- linux
# - osx
osx_image: xcode9.4
language: cpp
sudo: required
dist: trusty
dist: xenial
branches:
only:
- master
@ -11,19 +15,18 @@ env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: NZmvVuA0O9NJXVQ12tXQZHDJC2mbFgYNFcsicw0DgW1It2Nk5hxIkF0pfu4/Z59mhQuOPgRVjl5b0FKy2Axh0gkWc1DJEXGwNaiW5lpTMNWR1LJG5rxa8LrDUpFkycpbzfAFuTUZu5z3iYVv64XzELvBuqNGhPMu1LeBnrlech0jFNjkR9p5qtJGWb8zYcPMCC57rig8a9g1ABoVYS6UXjrKpx0946ZLRsE5ukc9pXsypGwPmOMyfzZkxxzIqFaxoE5JIEdaJTWba/6Za315ozYYIi/N35ROI1YAv5GHRe/Iw9XAa4vQpbDzjM7ZSsZdTvvQsSU598gD2xC6jFUKSrpW6GZKwM2x236fZLGnOk5Uw7DUbG+AwpcEmxBwoy9PjBl9ZF3tJykI0gROewCy8MODhdsVMKr1HGIMVBIJySm/RnNqtoDbYV8mYnSl5b8rwJiCajoiR8Zuv4CIfGneeH1a3DOQDPH/qkDsU6ilzF4ANsBlMUUpgY653KBMBmTlNuVZSH527tnD7Fg6JgHVuSQkTbRa1vSkR7Zcre604RZcAoaEdbX3bhVDasPPghU/I742L0RH3oQNlR09pPBDZ8kG7ydl4aPHwpCWnvXNM1vgxtGvnYLztwrse7IoaRXRYiMFmrso78WhMWUDKgvY4wV9aeUu0DtnMezZVIQwCKg=
- macos_qt_formula=qt
- secure: 1QK0yVyoOB+gf2I7XzvhXu9w/5lq4stBXIwJbVCTjz4Q4XVHCosURaW1MAgKzMrPnbFEwjyn5uQ8BwsvvfkuN1AZD0YXITgc7gyI+J1wQ/p/ljxRxglakU6WEgsTs2J5z9UmGac4YTXg+quK7YP3rv+zuGim2I2rhzImejyzp0Ym3kRCnNcy+SGBsiRaevRJMe00Ch8zGAbEhduQGeSoS6W0rcu02DNlQKiq5NktWsXR+TWWWVfIeIlQR/lbPsCd0pdxMaMv2QCY0rVbwrYxWJwr/Qe45dAdWp+8/C3PbXpeMSGxlLa33nJNX4Lf/djxbjm8KWk6edaXPajrjR/0iwcpwq0jg2Jt6XfEdnJt35F1gpXlc04sxStjG45uloOKCFYT0wdhIO1Lq+hDP54wypQl+JInd5qC001O7pwhVxO36EgKWqo8HD+BqGDBwsNj2engy9Qcp3wO6G0rLBPB3CrZsk9wrHVv5cSiQSLMhId3Xviu3ZI2qEDA+kgTvxrKrsnMj4bILVCyG5Ka2Mj22wIDW9e8oIab9oTdujax3DTN1GkD6QuOAGzwDsNwGASsgfoeZ+FUhgM75RlBWGMilgkmnF7EJ0oAXLEpjtABnEr2d4qHv+y08kOuTDBLB9ExzCIj024dYYYNLZrqPKx0ncHuCMG2QNj2aJAJEZtj1rQ=
addons:
apt:
sources:
- sourceline: 'ppa:openmw/openmw'
- sourceline: 'ppa:rakhimov/boost'
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8
packages: [
# Dev
cmake, clang-3.8, libunshield-dev, libtinyxml-dev,
g++-6,
cmake, clang-6.0, libunshield-dev, libtinyxml-dev,
g++-8,
# Tests
libgtest-dev, google-mock,
# Boost
@ -42,7 +45,7 @@ addons:
project:
name: "TES3MP/openmw-tes3mp"
description: "<Your project description here>"
notification_email: stas5978@gmail.com
notification_email: koncord@tes3mp.com
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE"
build_command: "make -j3"
branch_pattern: coverity_scan
@ -50,19 +53,21 @@ matrix:
include:
- os: linux
env:
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
compiler: clang
- os: linux
env:
- MATRIX_CC="CC=gcc-6 && CXX=g++-6"
- MATRIX_CC="CC=gcc-8 && CXX=g++-8"
- os: linux
env:
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
allow_failures:
- env:
- ANALYZE="scan-build-3.8 --use-cc clang-3.8 --use-c++ clang++-3.8 "
- MATRIX_CC="CC=clang-3.8 && CXX=clang++-3.8"
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
- env:
- ANALYZE="scan-build-6.0 --use-cc clang-6.0 --use-c++ clang++-6.0 "
- MATRIX_CC="CC=clang-6.0 && CXX=clang++-6.0"
before_install:
- ./CI/before_install.${TRAVIS_OS_NAME}.sh

View file

@ -22,6 +22,7 @@ Programmers
alexanderkjall
Alexander Nadeau (wareya)
Alexander Olofsson (Ace)
Alex S (docwest)
Allofich
Andrei Kortunov (akortunov)
AnyOldName3
@ -37,6 +38,7 @@ Programmers
Britt Mathis (galdor557)
Capostrophic
cc9cii
Cédric Mocquillon
Chris Boyce (slothlife)
Chris Robinson (KittyCat)
Cory F. Cohen (cfcohen)
@ -62,6 +64,8 @@ Programmers
Evgeniy Mineev (sandstranger)
Federico Guerra (FedeWar)
Fil Krynicki (filkry)
Finbar Crago(finbar-crago)
Florian Weber (Florianjw)
Gašper Sedej
gugus/gus
Hallfaer Tuilinn
@ -139,6 +143,7 @@ Programmers
Rohit Nirmal
Roman Melnik (Kromgart)
Roman Proskuryakov (kpp)
Roman Siromakha (elsid)
Sandy Carter (bwrsandman)
Scott Howard
scrawl
@ -171,6 +176,7 @@ Programmers
Documentation
-------------
Adam Bowen (adamnbowen)
Alejandro Sanchez (HiPhish)
Bodillium
Bret Curtis (psi29a)

View file

@ -1,8 +1,114 @@
0.45.0
------
Bug #1990: Sunrise/sunset not set correct
Bug #2131: Lustidrike's spell misses the player every time
Bug #2222: Fatigue's effect on selling price is backwards
Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped
Bug #2455: Creatures attacks degrade armor
Bug #2562: Forcing AI to activate a teleport door sometimes causes a crash
Bug #2626: Resurrecting the player does not resume the game
Bug #2772: Non-existing class or faction freezes the game
Bug #2835: Player able to slowly move when overencumbered
Bug #2852: No murder bounty when a player follower commits murder
Bug #2862: [macOS] Can't quit launcher using Command-Q or OpenMW->Quit
Bug #2872: Tab completion in console doesn't work with explicit reference
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
Bug #3249: Fixed revert function not updating views properly
Bug #3374: Touch spells not hitting kwama foragers
Bug #3486: [Mod] NPC Commands does not work
Bug #3591: Angled hit distance too low
Bug #3629: DB assassin attack never triggers creature spawning
Bug #3876: Landscape texture painting is misaligned
Bug #3897: Have Goodbye give all choices the effects of Goodbye
Bug #3911: [macOS] Typing in the "Content List name" dialog box produces double characters
Bug #3950: FLATTEN_STATIC_TRANSFORMS optimization breaks animated collision shapes
Bug #3993: Terrain texture blending map is not upscaled
Bug #3997: Almalexia doesn't pace
Bug #4036: Weird behaviour of AI packages if package target has non-unique ID
Bug #4047: OpenMW not reporting its version number in MacOS; OpenMW-CS not doing it fully
Bug #4110: Fixed undo / redo menu text losing the assigned shortcuts
Bug #4125: OpenMW logo cropped on bugtracker
Bug #4215: OpenMW shows book text after last EOL tag
Bug #4221: Characters get stuck in V-shaped terrain
Bug #4230: AiTravel package issues break some Tribunal quests
Bug #4251: Stationary NPCs do not return to their position after combat
Bug #4274: Pre-0.43 death animations are not forward-compatible with 0.43+
Bug #4286: Scripted animations can be interrupted
Bug #4291: Non-persistent actors that started the game as dead do not play death animations
Bug #4293: Faction members are not aware of faction ownerships in barter
Bug #4307: World cleanup should remove dead bodies only if death animation is finished
Bug #4311: OpenMW does not handle RootCollisionNode correctly
Bug #4327: Missing animations during spell/weapon stance switching
Bug #4358: Running animation is interrupted when magic mode is toggled
Bug #4368: Settings window ok button doesn't have key focus by default
Bug #4378: On-self absorb spells restore stats
Bug #4393: NPCs walk back to where they were after using ResetActors
Bug #4416: Handle exception if we try to play non-music file
Bug #4419: MRK NiStringExtraData is handled incorrectly
Bug #4426: RotateWorld behavior is incorrect
Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2
Bug #4431: "Lock 0" console command is a no-op
Bug #4432: Guards behaviour is incorrect if they do not have AI packages
Bug #4433: Guard behaviour is incorrect with Alarm = 0
Bug #4451: Script fails to compile when using "Begin, [ScriptName]" syntax
Bug #4452: Default terrain texture bleeds through texture transitions
Bug #4453: Quick keys behaviour is invalid for equipment
Bug #4454: AI opens doors too slow
Bug #4457: Item without CanCarry flag prevents shield autoequipping in dark areas
Bug #4458: AiWander console command handles idle chances incorrectly
Bug #4459: NotCell dialogue condition doesn't support partial matches
Bug #4460: Script function "Equip" doesn't bypass beast restrictions
Bug #4461: "Open" spell from non-player caster isn't a crime
Bug #4464: OpenMW keeps AiState cached storages even after we cancel AI packages
Bug #4469: Abot Silt Striders Model turn 90 degrees on horizontal
Bug #4474: No fallback when getVampireHead fails
Bug #4475: Scripted animations should not cause movement
Bug #4479: "Game" category on Advanced page is getting too long
Bug #4480: Segfault in QuickKeysMenu when item no longer in inventory
Bug #4489: Goodbye doesn't block dialogue hyperlinks
Bug #4490: PositionCell on player gives "Error: tried to add local script twice"
Bug #4494: Training cap based off Base Skill instead of Modified Skill
Bug #4495: Crossbow animations blending is buggy
Bug #4496: SpellTurnLeft and SpellTurnRight animation groups are unused
Bug #4497: File names starting with x or X are not classified as animation
Bug #4503: Cast and ExplodeSpell commands increase alteration skill
Bug #4510: Division by zero in MWMechanics::CreatureStats::setAttribute
Bug #4519: Knockdown does not discard movement in the 1st-person mode
Bug #4539: Paper Doll is affected by GUI scaling
Bug #4545: Creatures flee from werewolves
Bug #4551: Replace 0 sound range with default range separately
Bug #4553: Forcegreeting on non-actor opens a dialogue window which cannot be closed
Bug #4557: Topics with reserved names are handled differently from vanilla
Bug #4558: Mesh optimizer: check for reserved node name is case-sensitive
Bug #4563: Fast travel price logic checks destination cell instead of service actor cell
Bug #4565: Underwater view distance should be limited
Bug #4573: Player uses headtracking in the 1st-person mode
Bug #4574: Player turning animations are twitchy
Bug #4575: Weird result of attack animation blending with movement animations
Bug #4576: Reset of idle animations when attack can not be started
Feature #2606: Editor: Implemented (optional) case sensitive global search
Feature #3083: Play animation when NPC is casting spell via script
Feature #3103: Provide option for disposition to get increased by successful trade
Feature #3276: Editor: Search - Show number of (remaining) search results and indicate a search without any results
Feature #3641: Editor: Limit FPS in 3d preview window
Feature #3703: Ranged sneak attack criticals
Feature #4012: Editor: Write a log file if OpenCS crashes
Feature #4222: 360° screenshots
Feature #4256: Implement ToggleBorders (TB) console command
Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts
Feature #4345: Add equivalents for the command line commands to Launcher
Feature #4404: Editor: All EnumDelegate fields should have their items sorted alphabetically
Feature #4444: Per-group KF-animation files support
Feature #4466: Editor: Add option to ignore "Base" records when running verifier
Feature #4488: Make water shader rougher during rain
Feature #4509: Show count of enchanted items in stack in the spells list
Feature #4512: Editor: Use markers for lights and creatures levelled lists
Feature #4548: Weapon priority: use the actual chance to hit the target instead of weapon skill
Feature #4549: Weapon priority: use the actual damage in weapon rating calculations
Feature #4550: Weapon priority: make ranged weapon bonus more sensible
Task #2490: Don't open command prompt window on Release-mode builds automatically
Task #4545: Enable is_pod string test
0.44.0
------
@ -88,6 +194,7 @@
Bug #4412: openmw-iniimporter ignores data paths from config
Bug #4413: Moving with 0 strength uses all of your fatigue
Bug #4420: Camera flickering when I open up and close menus while sneaking
Bug #4424: [macOS] Cursor is either empty or garbage when compiled against macOS 10.13 SDK
Bug #4435: Item health is considered a signed integer
Bug #4441: Adding items to currently disabled weapon-wielding creatures crashes the game
Feature #1786: Round up encumbrance value in the encumbrance bar

View file

@ -15,7 +15,8 @@ sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
cd ~/
git clone https://github.com/TES3MP/RakNet
cd RakNet
cmake . -DRAKNET_ENABLE_DLL=OFF -DRAKNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
git clone https://github.com/TES3MP/CrabNet
cd CrabNet
cmake . -DCRABNET_ENABLE_DLL=OFF -DCRABNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
make -j3

View file

@ -4,7 +4,7 @@ brew update
brew outdated cmake || brew upgrade cmake
brew outdated pkgconfig || brew upgrade pkgconfig
brew install $macos_qt_formula
brew install qt
curl https://downloads.openmw.org/osx/dependencies/openmw-deps-c40905f.zip -o ~/openmw-deps.zip
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-100d2e0.zip -o ~/openmw-deps.zip
unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null

View file

@ -9,7 +9,7 @@ if [ ! -z "${MATRIX_CC}" ]; then
eval "${MATRIX_CC}"
fi
export RAKNET_ROOT=~/RakNet
export RAKNET_ROOT=~/CrabNet
export CODE_COVERAGE=0
if [ ! -z "${ANALYZE}" ]; then
@ -35,5 +35,5 @@ ${ANALYZE}cmake .. \
-DBINDIR=/usr/games \
-DCMAKE_BUILD_TYPE="None" \
-DUSE_SYSTEM_TINYXML=TRUE \
-DRakNet_LIBRARY_RELEASE=~/RakNet/lib/libRakNetLibStatic.a \
-DRakNet_LIBRARY_DEBUG=~/RakNet/lib/libRakNetLibStatic.a \
-DRakNet_LIBRARY_RELEASE=~/CrabNet/lib/libRakNetLibStatic.a \
-DRakNet_LIBRARY_DEBUG=~/CrabNet/lib/libRakNetLibStatic.a

View file

@ -1,4 +1,5 @@
#!/bin/bash
# set -x # turn-on for debugging
MISSINGTOOLS=0
@ -76,7 +77,6 @@ while [ $# -gt 0 ]; do
h )
cat <<EOF
Usage: $0 [-cdehkpuvV]
Options:
-c <Release/Debug>
Set the configuration, can also be set with environment variable CONFIGURATION.
@ -232,10 +232,9 @@ fi
case $VS_VERSION in
15|15.0|2017 )
GENERATOR="Visual Studio 15 2017"
TOOLSET="vc140"
TOOLSET_REAL="vc141"
TOOLSET="vc141"
MSVC_REAL_VER="15"
MSVC_VER="14"
MSVC_VER="14.1"
MSVC_YEAR="2015"
MSVC_DISPLAY_YEAR="2017"
;;
@ -243,9 +242,8 @@ case $VS_VERSION in
14|14.0|2015 )
GENERATOR="Visual Studio 14 2015"
TOOLSET="vc140"
TOOLSET_REAL="vc140"
MSVC_REAL_VER="14"
MSVC_VER="14"
MSVC_VER="14.0"
MSVC_YEAR="2015"
MSVC_DISPLAY_YEAR="2015"
;;
@ -253,9 +251,8 @@ case $VS_VERSION in
12|12.0|2013 )
GENERATOR="Visual Studio 12 2013"
TOOLSET="vc120"
TOOLSET_REAL="vc120"
MSVC_REAL_VER="12"
MSVC_VER="12"
MSVC_VER="12.0"
MSVC_YEAR="2013"
MSVC_DISPLAY_YEAR="2013"
;;
@ -325,9 +322,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
# Boost
if [ -z $APPVEYOR ]; then
download "Boost 1.61.0" \
"https://sourceforge.net/projects/boost/files/boost-binaries/1.61.0/boost_1_61_0-msvc-${MSVC_VER}.0-${BITS}.exe" \
"boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe"
download "Boost 1.67.0" \
"https://sourceforge.net/projects/boost/files/boost-binaries/1.67.0/boost_1_67_0-msvc-${MSVC_VER}-${BITS}.exe" \
"boost-1.67.0-msvc${MSVC_YEAR}-win${BITS}.exe"
fi
# Bullet
@ -365,8 +362,8 @@ if [ -z $SKIP_DOWNLOAD ]; then
QT_SUFFIX=""
fi
download "Qt 5.7.2" \
"https://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \
download "Qt 5.7.0" \
"https://download.qt.io/archive/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \
"qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \
"https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \
"qt-5-install.qs"
@ -403,9 +400,9 @@ echo
# Boost
if [ -z $APPVEYOR ]; then
printf "Boost 1.61.0... "
printf "Boost 1.67.0... "
else
if [ $MSVC_VER -eq 12 ]; then
if [ $MSVC_VER -eq 12.0 ]; then
printf "Boost 1.58.0 AppVeyor... "
else
printf "Boost 1.67.0 AppVeyor... "
@ -417,17 +414,28 @@ fi
BOOST_SDK="$(real_pwd)/Boost"
if [ -d Boost ] && grep "BOOST_VERSION 106100" Boost/boost/version.hpp > /dev/null; then
# Boost's installer is still based on ms-dos API that doesn't support larger than 260 char path names
# We work around this by installing to root of the current working drive and then move it to our deps
# get the current working drive's root, we'll install to that temporarily
CWD_DRIVE_ROOT="$(powershell -command '(get-location).Drive.Root')Boost_temp"
CWD_DRIVE_ROOT_BASH=$(echo "$CWD_DRIVE_ROOT" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
if [ -d CWD_DRIVE_ROOT_BASH ]; then
printf "Cannot continue, ${CWD_DRIVE_ROOT_BASH} aka ${CWD_DRIVE_ROOT} already exists. Please remove before re-running. ";
exit 1;
fi
if [ -d ${BOOST_SDK} ] && grep "BOOST_VERSION 106700" Boost/boost/version.hpp > /dev/null; then
printf "Exists. "
elif [ -z $SKIP_EXTRACT ]; then
rm -rf Boost
"${DEPS}/boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe" //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent
CI_EXTRA_INNO_OPTIONS=""
[ -n "$CI" ] && CI_EXTRA_INNO_OPTIONS="//SUPPRESSMSGBOXES //LOG='boost_install.log'"
"${DEPS}/boost-1.67.0-msvc${MSVC_YEAR}-win${BITS}.exe" //DIR="${CWD_DRIVE_ROOT}" //VERYSILENT //NORESTART ${CI_EXTRA_INNO_OPTIONS}
mv "${CWD_DRIVE_ROOT_BASH}" "${BOOST_SDK}"
fi
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.0"
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}"
add_cmake_opts -DBoost_COMPILER="-${TOOLSET}"
echo Done.
else
# Appveyor unstable has all the boost we need already
@ -444,19 +452,17 @@ fi
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.${LIB_SUFFIX}"
add_cmake_opts -DBoost_COMPILER="-${TOOLSET_REAL}"
add_cmake_opts -DBoost_COMPILER="-${TOOLSET}"
echo Done.
fi
}
cd $DEPS
echo
# Bullet
printf "Bullet 2.86... "
{
cd $DEPS_INSTALL
if [ -d Bullet ]; then
printf -- "Exists. (No version checking) "
elif [ -z $SKIP_EXTRACT ]; then
@ -464,49 +470,38 @@ printf "Bullet 2.86... "
eval 7z x -y "${DEPS}/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
mv "Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}" Bullet
fi
export BULLET_ROOT="$(real_pwd)/Bullet"
echo Done.
}
cd $DEPS
echo
# FFmpeg
printf "FFmpeg 3.2.4... "
{
cd $DEPS_INSTALL
if [ -d FFmpeg ] && grep "FFmpeg version: 3.2.4" FFmpeg/README.txt > /dev/null; then
printf "Exists. "
elif [ -z $SKIP_EXTRACT ]; then
rm -rf FFmpeg
eval 7z x -y "${DEPS}/ffmpeg-3.2.4-win${BITS}.zip" $STRIP
eval 7z x -y "${DEPS}/ffmpeg-3.2.4-dev-win${BITS}.zip" $STRIP
mv "ffmpeg-3.2.4-win${BITS}-shared" FFmpeg
cp -r "ffmpeg-3.2.4-win${BITS}-dev/"* FFmpeg/
rm -rf "ffmpeg-3.2.4-win${BITS}-dev"
fi
export FFMPEG_HOME="$(real_pwd)/FFmpeg"
add_runtime_dlls "$(pwd)/FFmpeg/bin/"{avcodec-57,avformat-57,avutil-55,swresample-2,swscale-4}.dll
if [ $BITS -eq 32 ]; then
add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\""
fi
echo Done.
}
cd $DEPS
echo
# MyGUI
printf "MyGUI 3.2.2... "
{
cd $DEPS_INSTALL
if [ -d MyGUI ] && \
grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
@ -518,21 +513,17 @@ printf "MyGUI 3.2.2... "
eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI
fi
export MYGUI_HOME="$(real_pwd)/MyGUI"
if [ $CONFIGURATION == "Debug" ]; then
SUFFIX="_d"
else
SUFFIX=""
fi
add_runtime_dlls "$(pwd)/MyGUI/bin/${CONFIGURATION}/MyGUIEngine${SUFFIX}.dll"
echo Done.
}
cd $DEPS
echo
# OpenAL
printf "OpenAL-Soft 1.17.2... "
{
@ -542,24 +533,18 @@ printf "OpenAL-Soft 1.17.2... "
rm -rf openal-soft-1.17.2-bin
eval 7z x -y OpenAL-Soft-1.17.2.zip $STRIP
fi
OPENAL_SDK="$(real_pwd)/openal-soft-1.17.2-bin"
add_cmake_opts -DOPENAL_INCLUDE_DIR="${OPENAL_SDK}/include/AL" \
-DOPENAL_LIBRARY="${OPENAL_SDK}/libs/Win${BITS}/OpenAL32.lib"
add_runtime_dlls "$(pwd)/openal-soft-1.17.2-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll"
echo Done.
}
cd $DEPS
echo
# OSG
printf "OSG 3.4.1-scrawl... "
{
cd $DEPS_INSTALL
if [ -d OSG ] && \
grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \
@ -571,28 +556,21 @@ printf "OSG 3.4.1-scrawl... "
eval 7z x -y "${DEPS}/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
mv "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG
fi
OSG_SDK="$(real_pwd)/OSG"
add_cmake_opts -DOSG_DIR="$OSG_SDK"
if [ $CONFIGURATION == "Debug" ]; then
SUFFIX="d"
else
SUFFIX=""
fi
add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \
"$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll
echo Done.
}
cd $DEPS
echo
# Qt
if [ -z $APPVEYOR ]; then
printf "Qt 5.7.0... "
@ -605,71 +583,53 @@ fi
else
SUFFIX=""
fi
if [ -z $APPVEYOR ]; then
cd $DEPS_INSTALL
QT_SDK="$(real_pwd)/Qt/5.7/msvc${MSVC_YEAR}${SUFFIX}"
if [ -d Qt ] && head -n2 Qt/InstallationLog.txt | grep "5.7.0" > /dev/null; then
printf "Exists. "
elif [ -z $SKIP_EXTRACT ]; then
rm -rf Qt
cp "${DEPS}/qt-5-install.qs" qt-install.qs
sed -i "s|INSTALL_DIR|$(real_pwd)/Qt|" qt-install.qs
sed -i "s/qt.VERSION.winBITS_msvcYEAR/qt.57.win${BITS}_msvc${MSVC_YEAR}${SUFFIX}/" qt-install.qs
printf -- "(Installation might take a while) "
"${DEPS}/qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" --script qt-install.qs --silent
mv qt-install.qs Qt/
echo Done.
printf " Cleaning up extraneous data... "
rm -r "$(real_pwd)/Qt/"{dist,Docs,Examples,Tools,vcredist,components.xml,MaintenanceTool.dat,MaintenanceTool.exe,MaintenanceTool.ini,network.xml,qt-install.qs}
fi
cd $QT_SDK
add_cmake_opts -DDESIRED_QT_VERSION=5 \
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
-DCMAKE_PREFIX_PATH="$QT_SDK"
if [ $CONFIGURATION == "Debug" ]; then
SUFFIX="d"
else
SUFFIX=""
fi
add_runtime_dlls "$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
add_qt_platform_dlls "$(pwd)/plugins/platforms/qwindows${SUFFIX}.dll"
echo Done.
else
QT_SDK="C:/Qt/5.10/msvc${MSVC_DISPLAY_YEAR}${SUFFIX}"
add_cmake_opts -DDESIRED_QT_VERSION=5 \
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
-DCMAKE_PREFIX_PATH="$QT_SDK"
if [ $CONFIGURATION == "Debug" ]; then
SUFFIX="d"
else
SUFFIX=""
fi
DIR=$(echo "${QT_SDK}" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
add_runtime_dlls "${DIR}/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
add_qt_platform_dlls "${DIR}/plugins/platforms/qwindows${SUFFIX}.dll"
echo Done.
fi
}
cd $DEPS
echo
# SDL2
printf "SDL 2.0.7... "
{
@ -679,26 +639,18 @@ printf "SDL 2.0.7... "
rm -rf SDL2-2.0.7
eval 7z x -y SDL2-2.0.7.zip $STRIP
fi
export SDL2DIR="$(real_pwd)/SDL2-2.0.7"
add_runtime_dlls "$(pwd)/SDL2-2.0.7/lib/x${ARCHSUFFIX}/SDL2.dll"
echo Done.
}
echo
cd $DEPS_INSTALL/..
echo
echo "Setting up OpenMW build..."
add_cmake_opts -DBUILD_BSATOOL=no \
-DBUILD_ESMTOOL=no \
-DBUILD_MYGUI_PLUGIN=no \
-DOPENMW_MP_BUILD=on
if [ ! -z $CI ]; then
case $STEP in
components )
@ -710,7 +662,6 @@ if [ ! -z $CI ]; then
-DBUILD_OPENMW=no \
-DBUILD_WIZARD=no
;;
openmw )
echo " Building subproject: OpenMW."
add_cmake_opts -DBUILD_ESSIMPORTER=no \
@ -719,7 +670,6 @@ if [ ! -z $CI ]; then
-DBUILD_OPENCS=no \
-DBUILD_WIZARD=no
;;
opencs )
echo " Building subproject: OpenCS."
add_cmake_opts -DBUILD_ESSIMPORTER=no \
@ -728,7 +678,6 @@ if [ ! -z $CI ]; then
-DBUILD_OPENMW=no \
-DBUILD_WIZARD=no
;;
misc )
echo " Building subprojects: Misc."
add_cmake_opts -DBUILD_OPENCS=no \
@ -736,7 +685,6 @@ if [ ! -z $CI ]; then
;;
esac
fi
# NOTE: Disable this when/if we want to run test cases
#if [ -z $CI ]; then
echo "- Copying Runtime DLLs..."
@ -745,16 +693,13 @@ fi
TARGET="$(basename "$DLL")"
if [[ "$DLL" == *":"* ]]; then
IFS=':'; SPLIT=( ${DLL} ); unset IFS
DLL=${SPLIT[0]}
TARGET=${SPLIT[1]}
fi
echo " ${TARGET}."
cp "$DLL" "$BUILD_CONFIG/$TARGET"
done
echo
echo "- OSG Plugin DLLs..."
mkdir -p $BUILD_CONFIG/osgPlugins-3.4.1
for DLL in $OSG_PLUGINS; do
@ -762,7 +707,6 @@ fi
cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.1
done
echo
echo "- Qt Platform DLLs..."
mkdir -p ${BUILD_CONFIG}/platforms
for DLL in $QT_PLATFORMS; do
@ -771,16 +715,13 @@ fi
done
echo
#fi
if [ -z $VERBOSE ]; then
printf -- "- Configuring... "
else
echo "- cmake .. $CMAKE_OPTS"
fi
run_cmd cmake .. $CMAKE_OPTS
RET=$?
if [ -z $VERBOSE ]; then
if [ $RET -eq 0 ]; then
echo Done.
@ -788,5 +729,4 @@ if [ -z $VERBOSE ]; then
echo Failed.
fi
fi
exit $RET

View file

@ -4,14 +4,14 @@ export CXX=clang++
export CC=clang
DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps"
QT_PATH=`brew --prefix $macos_qt_formula`
QT_PATH=`brew --prefix qt`
mkdir build
cd build
cmake \
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.9" \
-D CMAKE_OSX_SYSROOT="macosx10.12" \
-D CMAKE_OSX_SYSROOT="macosx10.13" \
-D CMAKE_BUILD_TYPE=Release \
-D OPENMW_OSX_DEPLOYMENT=TRUE \
-D DESIRED_QT_VERSION=5 \

View file

@ -140,16 +140,6 @@ endif()
find_package(RakNet REQUIRED)
include_directories(${RakNet_INCLUDES})
if (BUILD_OPENMW_MP OR BUILD_MASTER)
find_package(LuaJit REQUIRED)
find_package(Sol2 REQUIRED)
include_directories(${LuaJit_INCLUDE_DIRS} ${Sol2_INCLUDE_DIRS})
endif()
if (BUILD_MASTER)
find_package(OpenSSL REQUIRED)
include_directories(${OpenSSL_INCLUDE_DIRS})
endif()
# Dependencies
find_package(OpenGL REQUIRED)
@ -219,6 +209,7 @@ endif()
IF(BUILD_OPENMW OR BUILD_OPENCS)
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
set(USED_OSG_PLUGINS
osgdb_bmp
@ -259,11 +250,10 @@ IF(BUILD_OPENMW OR BUILD_OPENCS)
find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Bullet ${REQUIRED_BULLET_VERSION} REQUIRED COMPONENTS BulletCollision LinearMath)
ELSE()
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) # HACK: DO NOT MOVE THIS. Used for server only build, kept here to avoid merge conflicts above.
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) # HACK: DON'T TOUCH IT!
set(BOOST_COMPONENTS system filesystem program_options)
if(WIN32)
@ -676,10 +666,10 @@ if (WIN32)
endif()
if (BUILD_OPENMW)
# Release builds use the debug console
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
set_target_properties(tes3mp PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
# Release builds don't use the debug console
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
set_target_properties(tes3mp PROPERTIES COMPILE_DEFINITIONS_RELEASE "_WINDOWS")
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
endif()
# Play a bit with the warning levels
@ -690,7 +680,8 @@ if (WIN32)
# Warnings that aren't enabled normally and don't need to be enabled
# They're unneeded and sometimes completely retarded warnings that /Wall enables
# Not going to bother commenting them as they tend to warn on every standard library file
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625
4626 4628 4640 4668 4710 4711 4768 4820 4826 4917 4946 5032 5039 5045
# Warnings that are thrown on standard libraries and not OpenMW
4347 # Non-template function with same name and parameter count as template function
@ -711,6 +702,7 @@ if (WIN32)
# caused by MyGUI
4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception'
4297 # function assumed not to throw an exception but does
# OpenMW specific warnings
4099 # Type mismatch, declared class or struct is defined with other type
@ -744,7 +736,10 @@ if (WIN32)
endforeach(d)
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
if (BUILD_OPENMW)
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")

View file

@ -3,7 +3,7 @@ How to contribute to OpenMW
Not sure what to do with all your free time? Pick out a task from here:
https://bugs.openmw.org/
https://gitlab.com/OpenMW/openmw/issues
Currently, we are focused on completing the MW game experience and general polishing. Features out of this scope may be approved in some cases, but you should probably start a discussion first.

View file

@ -1,47 +1,49 @@
TES3MP
======
[![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp)
Copyright (c) 2008-2015, OpenMW Team
Copyright (c) 2016-2019, Stanislav Zhukov & David Cernat
TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source engine recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind".
[![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=0.7.0)](https://travis-ci.org/TES3MP/openmw-tes3mp)
* TES3MP version: TBD-rewrite
TES3MP is a project adding multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), an open-source game engine that supports playing "The Elder Scrolls III: Morrowind" by Bethesda Softworks.
* TES3MP version: 0.7.0-alpha
* OpenMW version: 0.44.0
* License: GPLv3 (see [LICENSE](https://github.com/TES3MP/openmw-tes3mp/blob/master/LICENSE) for more information)
Font Licenses:
* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVu Font License.txt](https://github.com/TES3MP/openmw-tes3mp/blob/master/files/mygui/DejaVu%20Font%20License.txt) for more information)
Project Status
Project status
--------------
[Version changelog](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-changelog.md)
As of version 0.6, TES3MP is playable in most respects. Player and NPC movement, animations, combat and spell casting are properly synchronized with small exceptions, as is picking up and dropping items in the world, using doors and levers, and adding and removing items from containers. Journal entries, faction stats and dialogue topics are also synchronized, allowing the majority of quests to work fine.
As of version 0.7.0, TES3MP is fully playable, providing very extensive player, NPC, world and quest synchronization, as well as state saving and loading, all of which are highly customizable via [serverside Lua scripts](https://github.com/TES3MP/CoreScripts).
[Serverside Lua scripts](https://github.com/TES3MP/CoreScripts) are used to save and load the state of most of the aforementioned.
Remaining gameplay problems mostly relate to AI and the synchronization of clientside script variables.
Please note that the master branch is an unfinished rewrite of a large part of the project and is not yet playable. You should use the [latest 0.6 release](https://github.com/TES3MP/openmw-tes3mp/releases/latest) for now.
Donations
---------------
You can benefit the project by donating on Patreon to our two developers, [David Cernat](https://www.patreon.com/davidcernat) and [Koncord](https://www.patreon.com/Koncord), as well as by supporting [OpenMW](https://openmw.org).
Contributing
--------------
---------------
Development has been relatively fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting or video showcases is greatly appreciated.
Helping us with documentation, bug hunting and video showcases is always greatly appreciated.
Test sessions are often advertised on [our Discord server](https://discord.gg/ECJk293) or in [our Steam group](https://steamcommunity.com/groups/mwmulti).
For code contributions, it's best to start out with modestly sized fixes and features and work your way up. There are so many different possible implementations of more major features many of which would cause undesirable code or vision conflicts with OpenMW that those should be talked over in advance with the existing developers before effort is spent on them.
Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have.
Getting Started
Getting started
---------------
* [Quickstart guide](https://github.com/TES3MP/openmw-tes3mp/wiki/Quickstart-guide)
* [Steam group](https://steamcommunity.com/groups/mwmulti) and its [detailed FAQ](https://steamcommunity.com/groups/mwmulti/discussions/1/353916184342480541/)
* [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=45)
* [Discord server](https://discord.gg/ECJk293)
* [Subreddit](https://www.reddit.com/r/tes3mp)
* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues)
Donations
---------------
You can benefit the project by contributing to the Patreon pages of our two developers, [Koncord](https://www.patreon.com/Koncord) and [David Cernat](https://www.patreon.com/davidcernat), as well as by supporting [OpenMW](https://openmw.org).

View file

@ -1,4 +1,5 @@
option(OPTION_TES3MP_PRE07 "Temporary. Pre 0.7.0 compatible mode." OFF)
set (CMAKE_CXX_STANDARD 14)
set(BROWSER_UI
${CMAKE_SOURCE_DIR}/files/tes3mp/ui/Main.ui
@ -16,7 +17,6 @@ set(BROWSER
PingUpdater.cpp
PingHelper.cpp
QueryHelper.cpp
Settings.cpp
${CMAKE_SOURCE_DIR}/files/tes3mp/browser.rc
)
@ -36,7 +36,6 @@ set(BROWSER_HEADER
netutils/Utils.hpp
netutils/QueryClient.hpp
Types.hpp
Settings.hpp
)
source_group(browser FILES ${BROWSER} ${BROWSER_HEADER})
@ -76,13 +75,6 @@ add_executable(tes3mp-browser
${UI_HDRS}
)
set_property(TARGET tes3mp-browser PROPERTY CXX_STANDARD 14)
if (OPTION_TES3MP_PRE07)
target_compile_definitions(tes3mp-browser PRIVATE TES3MP_PRE07)
endif (OPTION_TES3MP_PRE07)
if (WIN32)
INSTALL(TARGETS tes3mp-browser RUNTIME DESTINATION ".")
endif (WIN32)

View file

@ -13,8 +13,6 @@
#include <QJsonArray>
#include <QFile>
#include <QJsonDocument>
#include <apps/browser/netutils/Utils.hpp>
#include <QtWidgets/QFileDialog>
using namespace Process;
@ -33,6 +31,9 @@ MainWindow::MainWindow(QWidget *parent)
tblServerBrowser->setModel(proxyModel);
tblFavorites->setModel(proxyModel);
// Remove Favorites tab while it remains broken
tabWidget->removeTab(1);
tblServerBrowser->hideColumn(ServerData::ADDR);
tblFavorites->hideColumn(ServerData::ADDR);
@ -56,31 +57,12 @@ MainWindow::MainWindow(QWidget *parent)
connect(cBBoxWOPass, SIGNAL(toggled(bool)), this, SLOT(noPasswordSwitch(bool)));
connect(comboLatency, SIGNAL(currentIndexChanged(int)), this, SLOT(maxLatencyChanged(int)));
connect(leGamemode, SIGNAL(textChanged(const QString &)), this, SLOT(gamemodeChanged(const QString &)));
connect(pbModulePath, &QPushButton::clicked, [this](bool) {
QString str = QFileDialog::getExistingDirectory(this, tr("Module path"),
leModulePath->text(), QFileDialog::ShowDirsOnly);
if(!str.isEmpty())
leModulePath->setText(str);
});
loadFavorites();
queryHelper->refresh();
settingsMgr.loadBrowserSettings(*this);
#ifdef TES3MP_PRE07
gbModules->setTitle(tr("Plugins Path"));
chbAutosort->setVisible(false);
listModules->setVisible(false);
leAddModule->setVisible(false);
pbAddModule->setVisible(false);
pbUpModule->setVisible(false);
pbDownModule->setVisible(false);
pbRemModule->setVisible(false);
#endif
}
MainWindow::~MainWindow()
{
settingsMgr.saveBrowserSettings(*this);
delete mGameInvoker;
}
@ -89,9 +71,6 @@ void MainWindow::addServerAndUpdate(const QString &addr)
favorites->insertRow(0);
QModelIndex mi = favorites->index(0, ServerData::ADDR);
favorites->setData(mi, addr, Qt::EditRole);
/*auto address = addr.split(":");
auto data = getExtendedData(address[0].toLatin1(), address[1].toUShort());*/
//NetController::get()->updateInfo(favorites, mi);
//QueryClient::Update(RakNet::SystemAddress())
/*auto data = QueryClient::Get().Query();

View file

@ -9,7 +9,6 @@
#include "ui_Main.h"
#include "ServerModel.hpp"
#include "MySortFilterProxyModel.hpp"
#include "Settings.hpp"
#include <components/process/processinvoker.hpp>
class QueryHelper;
@ -40,7 +39,6 @@ private:
Process::ProcessInvoker *mGameInvoker;
ServerModel *browser, *favorites;
MySortFilterProxyModel *proxyModel;
SettingsMgr settingsMgr;
void loadFavorites();
};

View file

@ -1,198 +0,0 @@
//
// Created by koncord on 31.03.18.
//
#include "Settings.hpp"
#include <QDebug>
#include <components/files/configurationmanager.hpp>
#include <apps/browser/netutils/QueryClient.hpp>
#include "MainWindow.hpp"
std::string loadSettings (Settings::Manager & settings, const std::string &cfgName)
{
Files::ConfigurationManager mCfgMgr;
// Create the settings manager and load default settings file
const std::string localdefault = (mCfgMgr.getLocalPath() / (cfgName + "-default.cfg")).string();
const std::string globaldefault = (mCfgMgr.getGlobalPath() / (cfgName + "-default.cfg")).string();
// prefer local
if (boost::filesystem::exists(localdefault))
settings.loadDefault(localdefault);
else if (boost::filesystem::exists(globaldefault))
settings.loadDefault(globaldefault);
else
throw std::runtime_error ("No default settings file found! Make sure the file \"" + cfgName + "-default.cfg\" was properly installed.");
// load user settings if they exist
const std::string settingspath = (mCfgMgr.getUserConfigPath() / (cfgName + ".cfg")).string();
if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath);
return settingspath;
}
SettingsMgr::SettingsMgr()
{
clientCfg = loadSettings(clientMgr, "tes3mp-client");
switchMgr();
serverCfg = loadSettings(serverMgr, "tes3mp-server");
switchMgr();
std::string addr = clientMgr.getString("address", "Master");
int port = clientMgr.getInt("port", "Master");
QueryClient::Get().SetServer(addr, port);
}
void SettingsMgr::loadBrowserSettings(Ui::MainWindow &mw)
{
mw.comboLatency->setCurrentIndex(clientMgr.getInt("maxLatency", "Browser"));
mw.leGamemode->setText(QString::fromStdString(clientMgr.getString("gameMode", "Browser")));
mw.cBoxNotFull->setCheckState(clientMgr.getBool("notFull", "Browser") ? Qt::Checked : Qt::Unchecked);
mw.cBoxWithPlayers->setCheckState(clientMgr.getBool("withPlayers", "Browser") ? Qt::Checked : Qt::Unchecked);
mw.cBBoxWOPass->setCheckState(clientMgr.getBool("noPassword", "Browser") ? Qt::Checked : Qt::Unchecked);
mw.tblServerBrowser->sortByColumn(clientMgr.getInt("sortByCol", "Browser"),
clientMgr.getBool("sortByColAscending", "Browser") ? Qt::AscendingOrder : Qt::DescendingOrder);
loadClientSettings(mw);
switchMgr();
loadServerSettings(mw);
switchMgr();
}
void SettingsMgr::saveBrowserSettings(Ui::MainWindow &mw)
{
clientMgr.setInt("maxLatency", "Browser", mw.comboLatency->currentIndex());
clientMgr.setString("gameMode", "Browser", mw.leGamemode->text().toStdString());
clientMgr.setBool("notFull", "Browser", mw.cBoxNotFull->checkState() == Qt::Checked);
clientMgr.setBool("withPlayers", "Browser", mw.cBoxWithPlayers->checkState() == Qt::Checked);
clientMgr.setBool("noPassword", "Browser", mw.cBBoxWOPass->checkState() == Qt::Checked);
clientMgr.setInt("sortByCol", "Browser", mw.tblServerBrowser->horizontalHeader()->sortIndicatorSection());
clientMgr.setBool("sortByColAscending", "Browser", mw.tblServerBrowser->horizontalHeader()->sortIndicatorOrder() == Qt::AscendingOrder);
saveClientSettings(mw);
clientMgr.saveUser(clientCfg);
switchMgr();
saveServerSettings(mw);
switchMgr();
}
void SettingsMgr::loadClientSettings(Ui::MainWindow &mw)
{
mw.leClientAddress->setText(QString::fromStdString(clientMgr.getString("destinationAddress", "General")));
mw.leClientPort->setText(QString::fromStdString(clientMgr.getString("port", "General")));
mw.leClientPassword->setText(QString::fromStdString(clientMgr.getString("password", "General")));
mw.combLoglevel->setCurrentIndex(clientMgr.getInt("logLevel", "General"));
mw.leClientMAddress->setText(QString::fromStdString(clientMgr.getString("address", "Master")));
mw.leClientMPort->setText(QString::fromStdString(clientMgr.getString("port", "Master")));
mw.pbChatKey->setText(QString::fromStdString(clientMgr.getString("keySay", "Chat")));
mw.pbModeKey->setText(QString::fromStdString(clientMgr.getString("keyChatMode", "Chat")));
mw.sbPosX->setValue(clientMgr.getInt("x", "Chat"));
mw.sbPosY->setValue(clientMgr.getInt("y", "Chat"));
mw.sbPosW->setValue(clientMgr.getInt("w", "Chat"));
mw.sbPosH->setValue(clientMgr.getInt("h", "Chat"));
mw.sbDelay->setValue(clientMgr.getFloat("delay", "Chat"));
}
void SettingsMgr::saveClientSettings(Ui::MainWindow &mw)
{
clientMgr.setString("destinationAddress", "General", mw.leClientAddress->text().toStdString());
clientMgr.setString("port", "General", mw.leClientPort->text().toStdString());
clientMgr.setString("password", "General", mw.leClientPassword->text().toStdString());
clientMgr.setInt("logLevel", "General", mw.combLoglevel->currentIndex());
clientMgr.setString("address", "Master", mw.leClientMAddress->text().toStdString());
clientMgr.setString("port", "Master", mw.leClientMPort->text().toStdString());
clientMgr.setString("keySay", "Chat", mw.pbChatKey->text().toStdString());
clientMgr.setString("keyChatMode", "Chat", mw.pbModeKey->text().toStdString());
clientMgr.setInt("x", "Chat", mw.sbPosX->value());
clientMgr.setInt("y", "Chat", mw.sbPosY->value());
clientMgr.setInt("w", "Chat", mw.sbPosW->value());
clientMgr.setInt("h", "Chat", mw.sbPosH->value());
clientMgr.setFloat("delay", "Chat", mw.sbDelay->value());
}
void SettingsMgr::loadServerSettings(Ui::MainWindow &mw)
{
mw.leServerAddress->setText(QString::fromStdString(serverMgr.getString("localAddress", "General")));
mw.leServerPort->setText(QString::fromStdString(serverMgr.getString("port", "General")));
mw.sbMaxPlayers->setValue(serverMgr.getInt("maximumPlayers", "General"));
mw.leHostname->setText(QString::fromStdString(serverMgr.getString("hostname", "General")));
mw.combServerLoglevel->setCurrentIndex(serverMgr.getInt("logLevel", "General"));
mw.leServerPassword->setText(QString::fromStdString(serverMgr.getString("password", "General")));
mw.chbMSenabled->setCheckState(serverMgr.getBool("enabled", "MasterServer") ? Qt::Checked : Qt::Unchecked);
mw.leServerMaddress->setText(QString::fromStdString(serverMgr.getString("address", "MasterServer")));
mw.leServerMPort->setText(QString::fromStdString(serverMgr.getString("port", "MasterServer")));
mw.sbRate->setValue(serverMgr.getInt("rate", "MasterServer"));
#ifndef TES3MP_PRE07
mw.leModulePath->setText(QString::fromStdString(serverMgr.getString("home", "Modules")));
mw.chbAutosort->setCheckState(serverMgr.getBool("autoSort", "Modules") ? Qt::Checked : Qt::Unchecked);
#else
mw.leModulePath->setText(QString::fromStdString(serverMgr.getString("home", "Plugins")));
#endif
}
void SettingsMgr::saveServerSettings(Ui::MainWindow &mw)
{
serverMgr.setString("localAddress", "General", mw.leServerAddress->text().toStdString());
serverMgr.setString("port", "General", mw.leServerPort->text().toStdString());
serverMgr.setInt("maximumPlayers", "General", mw.sbMaxPlayers->value());
serverMgr.setString("hostname", "General", mw.leHostname->text().toStdString());
serverMgr.setInt("logLevel", "General", mw.combServerLoglevel->currentIndex());
serverMgr.setString("password", "General", mw.leServerPassword->text().toStdString());
serverMgr.setBool("enabled", "MasterServer", mw.chbMSenabled->checkState() == Qt::Checked);
serverMgr.setString("address", "MasterServer", mw.leServerMaddress->text().toStdString());
serverMgr.setString("port", "MasterServer", mw.leServerMPort->text().toStdString());
serverMgr.setInt("rate", "MasterServer", mw.sbRate->value());
#ifndef TES3MP_PRE07
serverMgr.setString("home", "Modules", mw.leModulePath->text().toStdString());
serverMgr.setBool("autoSort", "Modules", mw.chbAutosort->checkState() == Qt::Checked);
#else
serverMgr.setString("home", "Plugins", mw.leModulePath->text().toStdString());
#endif
serverMgr.saveUser(serverCfg);
}
void SettingsMgr::switchMgr()
{
static Settings::CategorySettingValueMap saveUserSettings;
static Settings::CategorySettingValueMap saveDefaultSettings;
static Settings::CategorySettingVector saveChangedSettings;
static bool currentMgrIsClient = true;
if(!currentMgrIsClient)
{
saveUserSettings.swap(clientMgr.mUserSettings);
saveDefaultSettings.swap(clientMgr.mDefaultSettings);
saveChangedSettings.swap(clientMgr.mChangedSettings);
qDebug() << "Manager switched to Client config";
}
else
{
saveUserSettings.swap(serverMgr.mUserSettings);
saveDefaultSettings.swap(serverMgr.mDefaultSettings);
saveChangedSettings.swap(serverMgr.mChangedSettings);
qDebug() << "Manager switched to Server config";
}
currentMgrIsClient = !currentMgrIsClient;
}

View file

@ -1,32 +0,0 @@
//
// Created by koncord on 31.03.18.
//
#pragma once
#include <components/settings/settings.hpp>
namespace Ui
{
class MainWindow;
}
class SettingsMgr
{
public:
SettingsMgr();
void loadBrowserSettings(Ui::MainWindow &mw);
void saveBrowserSettings(Ui::MainWindow &mw);
void loadClientSettings(Ui::MainWindow &mw);
void saveClientSettings(Ui::MainWindow &mw);
void loadServerSettings(Ui::MainWindow &mw);
void saveServerSettings(Ui::MainWindow &mw);
private:
Settings::Manager serverMgr, clientMgr;
std::string serverCfg, clientCfg;
void switchMgr();
};

View file

@ -4,8 +4,47 @@
#include <apps/browser/netutils/QueryClient.hpp>
#include "MainWindow.hpp"
std::string loadSettings (Settings::Manager & settings)
{
Files::ConfigurationManager mCfgMgr;
// Create the settings manager and load default settings file
const std::string localdefault = (mCfgMgr.getLocalPath() / "tes3mp-client-default.cfg").string();
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "tes3mp-client-default.cfg").string();
// prefer local
if (boost::filesystem::exists(localdefault))
settings.loadDefault(localdefault);
else if (boost::filesystem::exists(globaldefault))
settings.loadDefault(globaldefault);
else
throw std::runtime_error ("No default settings file found! Make sure the file \"tes3mp-client-default.cfg\" was properly installed.");
// load user settings if they exist
const std::string settingspath = (mCfgMgr.getUserConfigPath() / "tes3mp-client.cfg").string();
if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath);
return settingspath;
}
int main(int argc, char *argv[])
{
Settings::Manager mgr;
loadSettings(mgr);
std::string addr = mgr.getString("address", "Master");
int port = mgr.getInt("port", "Master");
// Is this an attempt to connect to the official master server at the old port? If so,
// redirect it to the correct port for the currently used fork of RakNet
if (Misc::StringUtils::ciEqual(addr, "master.tes3mp.com") && port == 25560)
port = 25561;
// initialize resources, if needed
// Q_INIT_RESOURCE(resfile);
QueryClient::Get().SetServer(addr, port);
QApplication app(argc, argv);
MainWindow d;

View file

@ -20,6 +20,7 @@ namespace ESSImport
item.mId = contItem.mItem.toString();
item.mCount = contItem.mCount;
item.mRelativeEquipmentSlot = -1;
item.mLockLevel = 0;
unsigned int itemCount = std::abs(item.mCount);
bool separateStacks = false;

View file

@ -8,6 +8,7 @@ set(LAUNCHER
settingspage.cpp
advancedpage.cpp
utils/cellnameloader.cpp
utils/profilescombobox.cpp
utils/textinputdialog.cpp
utils/lineedit.cpp
@ -24,6 +25,7 @@ set(LAUNCHER_HEADER
settingspage.hpp
advancedpage.hpp
utils/cellnameloader.hpp
utils/profilescombobox.hpp
utils/textinputdialog.hpp
utils/lineedit.hpp
@ -39,6 +41,7 @@ set(LAUNCHER_HEADER_MOC
settingspage.hpp
advancedpage.hpp
utils/cellnameloader.hpp
utils/textinputdialog.hpp
utils/profilescombobox.hpp
utils/lineedit.hpp

View file

@ -1,10 +1,18 @@
#include "advancedpage.hpp"
#include <components/files/configurationmanager.hpp>
#include <components/config/gamesettings.hpp>
#include <components/config/launchersettings.hpp>
#include <QFileDialog>
#include <QCompleter>
#include <components/contentselector/view/contentselector.hpp>
#include <components/contentselector/model/esmfile.hpp>
Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent)
Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg,
Config::GameSettings &gameSettings,
Settings::Manager &engineSettings, QWidget *parent)
: QWidget(parent)
, mCfgMgr(cfg)
, mGameSettings(gameSettings)
, mEngineSettings(engineSettings)
{
setObjectName ("AdvancedPage");
@ -13,23 +21,61 @@ Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, Settings:
loadSettings();
}
void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames) {
// Set up an auto-completer for the "Start default character at" field
auto *completer = new QCompleter(cellNames);
completer->setCompletionMode(QCompleter::PopupCompletion);
completer->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
startDefaultCharacterAtField->setCompleter(completer);
}
void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state) {
startDefaultCharacterAtLabel->setEnabled(state == Qt::Checked);
startDefaultCharacterAtField->setEnabled(state == Qt::Checked);
}
void Launcher::AdvancedPage::on_runScriptAfterStartupBrowseButton_clicked()
{
QString scriptFile = QFileDialog::getOpenFileName(
this,
QObject::tr("Select script file"),
QDir::currentPath(),
QString(tr("Text file (*.txt)")));
if (scriptFile.isEmpty())
return;
QFileInfo info(scriptFile);
if (!info.exists() || !info.isReadable())
return;
const QString path(QDir::toNativeSeparators(info.absoluteFilePath()));
runScriptAfterStartupField->setText(path);
}
bool Launcher::AdvancedPage::loadSettings()
{
// Testing
bool skipMenu = mGameSettings.value("skip-menu").toInt() == 1;
if (skipMenu) {
skipMenuCheckBox->setCheckState(Qt::Checked);
}
startDefaultCharacterAtLabel->setEnabled(skipMenu);
startDefaultCharacterAtField->setEnabled(skipMenu);
startDefaultCharacterAtField->setText(mGameSettings.value("start"));
runScriptAfterStartupField->setText(mGameSettings.value("script-run"));
// Game Settings
loadSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
loadSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
loadSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
loadSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
// Expected values are (0, 1, 2, 3)
int showOwnedIndex = mEngineSettings.getInt("show owned", "Game");
// Match the index with the option. Will default to 0 if invalid.
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
loadSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game");
loadSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
loadSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
// Input Settings
loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");
@ -40,6 +86,16 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves"));
// User Interface Settings
loadSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
loadSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
int showOwnedIndex = mEngineSettings.getInt("show owned", "Game");
// Match the index with the option (only 0, 1, 2, or 3 are valid). Will default to 0 if invalid.
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
// Other Settings
QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper();
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
@ -54,19 +110,27 @@ void Launcher::AdvancedPage::saveSettings()
// Ensure we only set the new settings if they changed. This is to avoid cluttering the
// user settings file (which by definition should only contain settings the user has touched)
// Testing
int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked;
if (skipMenu != mGameSettings.value("skip-menu").toInt())
mGameSettings.setValue("skip-menu", QString::number(skipMenu));
QString startCell = startDefaultCharacterAtField->text();
if (startCell != mGameSettings.value("start")) {
mGameSettings.setValue("start", startCell);
}
QString scriptRun = runScriptAfterStartupField->text();
if (scriptRun != mGameSettings.value("script-run"))
mGameSettings.setValue("script-run", scriptRun);
// Game Settings
saveSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
saveSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
saveSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game"))
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
saveSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game");
saveSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
saveSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
// Input Settings
saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");
@ -80,6 +144,15 @@ void Launcher::AdvancedPage::saveSettings()
mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksaves);
}
// User Interface Settings
saveSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
saveSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game"))
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
// Other Settings
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General"))
@ -96,3 +169,8 @@ void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::str
if (cValue != mEngineSettings.getBool(setting, group))
mEngineSettings.setBool(setting, group, cValue);
}
void Launcher::AdvancedPage::slotLoadedCellsChanged(QStringList cellNames)
{
loadCellsForAutocomplete(cellNames);
}

View file

@ -8,6 +8,7 @@
#include <components/settings/settings.hpp>
namespace Files { struct ConfigurationManager; }
namespace Config { class GameSettings; }
namespace Launcher
{
@ -16,15 +17,29 @@ namespace Launcher
Q_OBJECT
public:
AdvancedPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent = 0);
AdvancedPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
Settings::Manager &engineSettings, QWidget *parent = 0);
bool loadSettings();
void saveSettings();
public slots:
void slotLoadedCellsChanged(QStringList cellNames);
private slots:
void on_skipMenuCheckBox_stateChanged(int state);
void on_runScriptAfterStartupBrowseButton_clicked();
private:
Files::ConfigurationManager &mCfgMgr;
Config::GameSettings &mGameSettings;
Settings::Manager &mEngineSettings;
/**
* Load the cells associated with the given content files for use in autocomplete
* @param filePaths the file paths of the content files to be examined
*/
void loadCellsForAutocomplete(QStringList filePaths);
void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
void saveSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
};

View file

@ -7,7 +7,10 @@
#include <QCheckBox>
#include <QMenu>
#include <QSortFilterProxyModel>
#include <thread>
#include <mutex>
#include <apps/launcher/utils/cellnameloader.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/contentselector/model/esmfile.hpp>
@ -16,6 +19,7 @@
#include <components/config/gamesettings.hpp>
#include <components/config/launchersettings.hpp>
#include <iostream>
#include "utils/textinputdialog.hpp"
#include "utils/profilescombobox.hpp"
@ -40,6 +44,13 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config:
buildView();
loadSettings();
// Connect signal and slot after the settings have been loaded. We only care about the user changing
// the addons and don't want to get signals of the system doing it during startup.
connect(mSelector, SIGNAL(signalAddonDataChanged(QModelIndex,QModelIndex)),
this, SLOT(slotAddonDataChanged()));
// Call manually to indicate all changes to addon data during startup.
slotAddonDataChanged();
}
void Launcher::DataFilesPage::buildView()
@ -142,6 +153,17 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile)
mGameSettings.setContentList(fileNames);
}
QStringList Launcher::DataFilesPage::selectedFilePaths()
{
//retrieve the files selected for the profile
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
QStringList filePaths;
foreach(const ContentSelectorModel::EsmFile *item, items) {
filePaths.append(item->filePath());
}
return filePaths;
}
void Launcher::DataFilesPage::removeProfile(const QString &profile)
{
mLauncherSettings.removeContentList(profile);
@ -308,3 +330,31 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
return (msgBox.clickedButton() == deleteButton);
}
void Launcher::DataFilesPage::slotAddonDataChanged()
{
QStringList selectedFiles = selectedFilePaths();
if (previousSelectedFiles != selectedFiles) {
previousSelectedFiles = selectedFiles;
// Loading cells for core Morrowind + Expansions takes about 0.2 seconds, which is enough to cause a
// barely perceptible UI lag. Splitting into its own thread to alleviate that.
std::thread loadCellsThread(&DataFilesPage::reloadCells, this, selectedFiles);
loadCellsThread.detach();
}
}
// Mutex lock to run reloadCells synchronously.
std::mutex _reloadCellsMutex;
void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles)
{
// Use a mutex lock so that we can prevent two threads from executing the rest of this code at the same time
// Based on https://stackoverflow.com/a/5429695/531762
std::unique_lock<std::mutex> lock(_reloadCellsMutex);
// The following code will run only if there is not another thread currently running it
CellNameLoader cellNameLoader;
QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles));
std::sort(cellNamesList.begin(), cellNamesList.end());
emit signalLoadedCellsChanged(cellNamesList);
}

View file

@ -7,6 +7,7 @@
#include <QDir>
#include <QFile>
#include <QStringList>
class QSortFilterProxyModel;
class QAbstractItemModel;
@ -41,8 +42,15 @@ namespace Launcher
void saveSettings(const QString &profile = "");
bool loadSettings();
/**
* Returns the file paths of all selected content files
* @return the file paths of all selected content files
*/
QStringList selectedFilePaths();
signals:
void signalProfileChanged (int index);
void signalLoadedCellsChanged(QStringList selectedFiles);
public slots:
void slotProfileChanged (int index);
@ -52,6 +60,7 @@ namespace Launcher
void slotProfileChangedByUser(const QString &previous, const QString &current);
void slotProfileRenamed(const QString &previous, const QString &current);
void slotProfileDeleted(const QString &item);
void slotAddonDataChanged ();
void updateOkButton(const QString &text);
@ -72,7 +81,7 @@ namespace Launcher
Config::LauncherSettings &mLauncherSettings;
QString mPreviousProfile;
QStringList previousSelectedFiles;
QString mDataLocal;
void setPluginsCheckstates(Qt::CheckState state);
@ -87,6 +96,7 @@ namespace Launcher
void addProfile (const QString &profile, bool setAsCurrent);
void checkForDefaultProfile();
void populateFileViews(const QString& contentModelName);
void reloadCells(QStringList selectedFiles);
class PathIterator
{

View file

@ -1,6 +1,7 @@
#include "graphicspage.hpp"
#include <boost/math/common_factor.hpp>
#include <csignal>
#include <QDesktopWidget>
#include <QMessageBox>
#include <QDir>
@ -11,6 +12,7 @@
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
#include <SDL.h>
#include <SDL_video.h>
#include <components/files/configurationmanager.hpp>
@ -46,8 +48,28 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, Settings:
}
bool Launcher::GraphicsPage::connectToSdl() {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
// Required for determining screen resolution and such on the Graphics tab
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
return false;
}
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
return true;
}
bool Launcher::GraphicsPage::setupSDL()
{
bool sdlConnectSuccessful = connectToSdl();
if (!sdlConnectSuccessful)
{
return false;
}
int displays = SDL_GetNumVideoDisplays();
if (displays < 0)
@ -67,6 +89,9 @@ bool Launcher::GraphicsPage::setupSDL()
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
}
// Disconnect from SDL processes
SDL_Quit();
return true;
}

View file

@ -37,6 +37,11 @@ namespace Launcher
QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution();
/**
* Connect to the SDL so that we can use it to determine graphics
* @return whether or not connecting to SDL is successful
*/
bool connectToSdl();
bool setupSDL();
};
}

View file

@ -1,5 +1,4 @@
#include <iostream>
#include <csignal>
#include <QApplication>
#include <QTextCodec>
@ -12,24 +11,12 @@
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
#include <SDL.h>
#include "maindialog.hpp"
int main(int argc, char *argv[])
{
try
{
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
qDebug() << "SDL_Init failed: " << QString::fromUtf8(SDL_GetError());
return 0;
}
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
QApplication app(argc, argv);
// Now we make sure the current dir is set to application path
@ -46,9 +33,7 @@ int main(int argc, char *argv[])
if (result == Launcher::FirstRunDialogResultContinue)
mainWin.show();
int returnValue = app.exec();
SDL_Quit();
return returnValue;
return app.exec();
}
catch (std::exception& e)
{

View file

@ -90,19 +90,19 @@ void Launcher::MainDialog::createIcons()
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget);
graphicsButton->setIcon(QIcon::fromTheme("video-display"));
graphicsButton->setIcon(QIcon(":/images/preferences-video.png"));
graphicsButton->setText(tr("Graphics"));
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *settingsButton = new QListWidgetItem(iconWidget);
settingsButton->setIcon(QIcon::fromTheme("preferences-system"));
settingsButton->setIcon(QIcon(":/images/preferences.png"));
settingsButton->setText(tr("Settings"));
settingsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
settingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *advancedButton = new QListWidgetItem(iconWidget);
advancedButton->setIcon(QIcon::fromTheme("emblem-system"));
advancedButton->setIcon(QIcon(":/images/preferences-advanced.png"));
advancedButton->setText(tr("Advanced"));
advancedButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
advancedButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
@ -119,7 +119,7 @@ void Launcher::MainDialog::createPages()
mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
mGraphicsPage = new GraphicsPage(mCfgMgr, mEngineSettings, this);
mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
mAdvancedPage = new AdvancedPage(mCfgMgr, mEngineSettings, this);
mAdvancedPage = new AdvancedPage(mCfgMgr, mGameSettings, mEngineSettings, this);
// Set the combobox of the play page to imitate the combobox on the datafilespage
mPlayPage->setProfilesModel(mDataFilesPage->profilesModel());
@ -139,6 +139,8 @@ void Launcher::MainDialog::createPages()
connect(mPlayPage, SIGNAL(signalProfileChanged(int)), mDataFilesPage, SLOT(slotProfileChanged(int)));
connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int)));
// Using Qt::QueuedConnection because signal is emitted in a subthread and slot is in the main thread
connect(mDataFilesPage, SIGNAL(signalLoadedCellsChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList)), Qt::QueuedConnection);
}

View file

@ -0,0 +1,48 @@
#include "cellnameloader.hpp"
#include <components/esm/loadcell.hpp>
#include <components/contentselector/view/contentselector.hpp>
QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
{
QSet<QString> cellNames;
ESM::ESMReader esmReader;
// Loop through all content files
for (auto &contentPath : contentPaths) {
esmReader.open(contentPath.toStdString());
// Loop through all records
while(esmReader.hasMoreRecs())
{
ESM::NAME recordName = esmReader.getRecName();
esmReader.getRecHeader();
if (isCellRecord(recordName)) {
QString cellName = getCellName(esmReader);
if (!cellName.isEmpty()) {
cellNames.insert(cellName);
}
}
// Stop loading content for this record and continue to the next
esmReader.skipRecord();
}
}
return cellNames;
}
bool CellNameLoader::isCellRecord(ESM::NAME &recordName)
{
return recordName.intval == ESM::REC_CELL;
}
QString CellNameLoader::getCellName(ESM::ESMReader &esmReader)
{
ESM::Cell cell;
bool isDeleted = false;
cell.loadNameAndData(esmReader, isDeleted);
return QString::fromStdString(cell.mName);
}

View file

@ -0,0 +1,41 @@
#ifndef OPENMW_CELLNAMELOADER_H
#define OPENMW_CELLNAMELOADER_H
#include <QComboBox>
#include <QSet>
#include <QString>
#include <components/esm/esmreader.hpp>
namespace ESM {class ESMReader; struct Cell;}
namespace ContentSelectorView {class ContentSelector;}
class CellNameLoader {
public:
/**
* Returns the names of all cells contained within the given content files
* @param contentPaths the file paths of each content file to be examined
* @return the names of all cells
*/
QSet<QString> getCellNames(QStringList &contentPaths);
private:
/**
* Returns whether or not the given record is of type "Cell"
* @param name The name associated with the record
* @return whether or not the given record is of type "Cell"
*/
bool isCellRecord(ESM::NAME &name);
/**
* Returns the name of the cell
* @param esmReader the reader currently pointed to a loaded cell
* @return the name of the cell
*/
QString getCellName(ESM::ESMReader &esmReader);
};
#endif //OPENMW_CELLNAMELOADER_H

View file

@ -1,69 +0,0 @@
//
// Created by koncord on 04.09.17.
//
#include "AdminRest.hpp"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "RestUtils.hpp"
using namespace std;
using namespace chrono;
using namespace boost::property_tree;
AdminRest::AdminRest(const std::string &cert, const std::string &key, const std::string &verifyFile,
unsigned short port, std::shared_ptr<MasterServer> master) : httpServer(cert, key, verifyFile), master(master)
{
httpServer.config.port = port;
}
void AdminRest::start()
{
static const string AdminArea = "^/api/admin?";
httpServer.resource[AdminArea]["POST"] = [this](auto response, auto request) {
cout << request->method << endl;
cout << request->path << endl;
cout << request->http_version << endl;
for (auto &header : request->header)
cout << header.first << ": " << header.second << endl;
string resp;
master->luaStuff([&request, &response, &resp](sol::state &state) {
sol::protected_function func = state["OnAdminRequest"];
sol::protected_function_result result = func.call(request->remote_endpoint_address, request->content.string());
if (result.valid())
*response << result.get<string>();
else
{
cerr << "Error: " << result.get<string>() << endl;
*response << response500;
}
});
};
/*httpServer.on_error = [](auto request, const boost::system::error_code& err)
{
std::cerr << "Error: " << err.message() << " " << err.category().name() << std::endl;
};*/
httpServer.default_resource["GET"] = [](auto response, auto /*request*/) {
cout << "Default request" << endl;
*response << response400;
};
thr = thread([this](){httpServer.start();});
}
void AdminRest::stop()
{
httpServer.stop();
if(thr.joinable())
thr.join();
}

View file

@ -1,25 +0,0 @@
//
// Created by koncord on 04.09.17.
//
#pragma once
#include "SimpleWeb/https_server.hpp"
#include "MasterServer.hpp"
typedef SimpleWeb::Server<SimpleWeb::HTTPS> HttpsServer;
class AdminRest
{
public:
AdminRest(const std::string &cert, const std::string &key, const std::string &verifyFile, unsigned short port, std::shared_ptr<MasterServer> master);
void start();
void stop();
private:
HttpsServer httpServer;
std::shared_ptr<MasterServer> master;
std::thread thr;
};

View file

@ -1,13 +1,14 @@
project(masterserver)
#set(CMAKE_CXX_STANDARD 14)
add_definitions(-std=gnu++14)
include_directories("./")
set(SOURCE_FILES main.cpp MasterServer.cpp MasterServer.hpp RestServer.cpp RestServer.hpp AdminRest.cpp)
set(SOURCE_FILES main.cpp MasterServer.cpp MasterServer.hpp RestServer.cpp RestServer.hpp)
add_executable(masterserver ${SOURCE_FILES})
target_link_libraries(masterserver ${RakNet_LIBRARY} ${LuaJit_LIBRARIES} ${OPENSSL_LIBRARIES} components)
set_property(TARGET masterserver PROPERTY CXX_STANDARD 14)
target_link_libraries(masterserver ${RakNet_LIBRARY} components)
option(BUILD_MASTER_TEST "build master server test program" OFF)

View file

@ -12,54 +12,19 @@
#include <components/openmw-mp/Master/PacketMasterUpdate.hpp>
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
#include <components/openmw-mp/Version.hpp>
#include <components/openmw-mp/Utils.hpp>
#include <boost/filesystem.hpp>
using namespace RakNet;
using namespace std;
using namespace mwmp;
using namespace chrono;
MasterServer::MasterServer(const std::string &luaScript)
MasterServer::MasterServer(unsigned short maxConnections, unsigned short port)
{
state.open_libraries();
boost::filesystem::path absPath = boost::filesystem::absolute(luaScript);
std::string package_path = state["package"]["path"];
state["package"]["path"] = Utils::convertPath(absPath.parent_path().string() + "/?.lua") + ";" + package_path;
state.set_function("BanAddress", &MasterServer::ban, this);
state.set_function("UnbanAddress", &MasterServer::unban, this);
state.script_file(luaScript);
sol::table config = state["config"];
if (config.get_type() != sol::type::table)
throw runtime_error("config is not correct");
sol::object maxConnections = config["maxConnections"];
if (maxConnections.get_type() != sol::type::number)
throw runtime_error("config.maxConnections is not correct");
sol::object port = config["port"];
if (port.get_type() != sol::type::number)
throw runtime_error("config.port is not correct");
state.new_usertype<MasterServer::SServer>("Server",
"name", sol::property(&MasterServer::SServer::GetName),
"gamemode", sol::property(&MasterServer::SServer::GetGameMode),
"version", sol::property(&MasterServer::SServer::GetVersion)
);
peer = RakPeerInterface::GetInstance();
sockdescr = SocketDescriptor(port.as<unsigned short>(), nullptr);
peer->Startup(maxConnections.as<unsigned short>(), &sockdescr, 1, 1000);
peer->SetLimitIPConnectionFrequency(true);
sockdescr = SocketDescriptor(port, 0);
peer->Startup(maxConnections, &sockdescr, 1, 1000);
peer->SetMaximumIncomingConnections(maxConnections.as<unsigned short>());
peer->SetMaximumIncomingConnections(maxConnections);
peer->SetIncomingPassword(TES3MP_MASTERSERVER_PASSW, (int) strlen(TES3MP_MASTERSERVER_PASSW));
run = false;
}
@ -87,13 +52,6 @@ void MasterServer::Thread()
PacketMasterAnnounce pma(peer);
pma.SetSendStream(&send);
luaStuff([](sol::state &state) {
sol::protected_function func = state["OnInit"];
sol::protected_function_result result = func.call();
if (!result.valid())
cerr << "Error: " << result.get<string>() << endl;
});
while (run)
{
Packet *packet = peer->Receive();
@ -109,9 +67,9 @@ void MasterServer::Thread()
servers.erase(it++);
else ++it;
}
for (auto id = pendingACKs.begin(); id != pendingACKs.end();)
for(auto id = pendingACKs.begin(); id != pendingACKs.end();)
{
if (now - id->second >= 30s)
if(now - id->second >= 30s)
{
cout << "timeout: " << peer->GetSystemAddressFromGuid(id->first).ToString() << endl;
peer->CloseConnection(id->first, true);
@ -155,7 +113,7 @@ void MasterServer::Thread()
SystemAddress addr;
data.Read(addr); // update 1 server
auto it = servers.find(addr);
ServerIter it = servers.find(addr);
if (it != servers.end())
{
pair<SystemAddress, QueryData> pairPtr(it->first, static_cast<QueryData>(it->second));
@ -169,7 +127,7 @@ void MasterServer::Thread()
}
case ID_MASTER_ANNOUNCE:
{
auto iter = servers.find(packet->systemAddress);
ServerIter iter = servers.find(packet->systemAddress);
pma.SetReadStream(&data);
SServer server;
@ -183,26 +141,6 @@ void MasterServer::Thread()
pendingACKs[packet->guid] = steady_clock::now();
};
auto isServerValid = [&](const SServer &sserver) {
bool ret = false;
auto addr = packet->systemAddress.ToString(false);
lock_guard<mutex> lock(banMutex);
if (peer->IsBanned(addr)) // check if address is banned
return false;
luaStuff([&ret, &packet, &sserver, &addr](sol::state &state) {
sol::protected_function func = state["OnServerAnnounce"];
sol::protected_function_result result = func.call(addr, sserver);
if (result.valid())
ret = result.get<bool>();
else
cerr << "Error: " << result.get<string>() << endl;
});
return ret;
};
if (iter != servers.end())
{
if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_DELETE)
@ -214,19 +152,9 @@ void MasterServer::Thread()
}
else if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_ANNOUNCE)
{
if (isServerValid(server))
{
cout << "Updated";
iter->second = server;
keepAliveFunc();
}
else
{
cout << "Update rejected";
servers.erase(iter);
pendingACKs.erase(packet->guid);
}
cout << "Updated";
iter->second = server;
keepAliveFunc();
}
else
{
@ -236,14 +164,9 @@ void MasterServer::Thread()
}
else if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_ANNOUNCE)
{
if (isServerValid(server))
{
cout << "Added";
iter = servers.insert({packet->systemAddress, server}).first;
keepAliveFunc();
}
else
cout << "Adding rejected";
cout << "Added";
iter = servers.insert({packet->systemAddress, server}).first;
keepAliveFunc();
}
else
{
@ -263,8 +186,7 @@ void MasterServer::Thread()
peer->CloseConnection(packet->systemAddress, true);
break;
default:
cout << "Wrong packet. id " << (unsigned) packet->data[0] << " packet length "
<< packet->length << " from " << packet->systemAddress.ToString() << endl;
cout << "Wrong packet. id " << (unsigned) packet->data[0] << " packet length " << packet->length << " from " << packet->systemAddress.ToString() << endl;
peer->CloseConnection(packet->systemAddress, true);
}
}
@ -312,22 +234,3 @@ MasterServer::ServerMap *MasterServer::GetServers()
{
return &servers;
}
void MasterServer::luaStuff(std::function<void(sol::state &)> f)
{
lock_guard<mutex> lock(luaMutex);
f(state);
}
void MasterServer::ban(const std::string &addr)
{
lock_guard<mutex> lock(banMutex);
peer->AddToBanList(addr.c_str());
}
void MasterServer::unban(const std::string &addr)
{
lock_guard<mutex> lock(banMutex);
peer->RemoveFromBanList(addr.c_str());
}

View file

@ -9,12 +9,18 @@
#include <chrono>
#include <RakPeerInterface.h>
#include <components/openmw-mp/Master/MasterData.hpp>
#include <sol.hpp>
#include <mutex>
class MasterServer
{
public:
struct Ban
{
RakNet::SystemAddress sa;
bool permanent;
struct Date
{
} date;
};
struct SServer : QueryData
{
std::chrono::steady_clock::time_point lastUpdate;
@ -23,7 +29,7 @@ public:
//typedef ServerMap::const_iterator ServerCIter;
typedef ServerMap::iterator ServerIter;
explicit MasterServer(const std::string &luaScript);
MasterServer(unsigned short maxConnections, unsigned short port);
~MasterServer();
void Start();
@ -32,10 +38,6 @@ public:
void Wait();
ServerMap* GetServers();
void luaStuff(std::function<void(sol::state &)> f);
void ban(const std::string &addr);
void unban(const std::string &addr);
private:
void Thread();
@ -47,9 +49,6 @@ private:
ServerMap servers;
bool run;
std::map<RakNet::RakNetGUID, std::chrono::steady_clock::time_point> pendingACKs;
sol::state state;
std::mutex luaMutex;
std::mutex banMutex;
};

View file

@ -7,12 +7,22 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "RestUtils.hpp"
using namespace std;
using namespace chrono;
using namespace boost::property_tree;
static string response201 = "HTTP/1.1 201 Created\r\nContent-Length: 7\r\n\r\nCreated";
static string response202 = "HTTP/1.1 202 Accepted\r\nContent-Length: 8\r\n\r\nAccepted";
static string response400 = "HTTP/1.1 400 Bad Request\r\nContent-Length: 11\r\n\r\nbad request";
inline void ResponseStr(HttpServer::Response &response, string content, string type = "", string code = "200 OK")
{
response << "HTTP/1.1 " << code << "\r\n";
if (!type.empty())
response << "Content-Type: " << type <<"\r\n";
response << "Content-Length: " << content.length() << "\r\n\r\n" << content;
}
inline void ptreeToServer(boost::property_tree::ptree &pt, MasterServer::SServer &server)
{
server.SetName(pt.get<string>("hostname").c_str());
@ -60,7 +70,7 @@ void RestServer::start()
auto port = (unsigned short)stoi(&(addr[addr.find(':')+1]));
queryToStringStream(ss, "server", serverMap->at(RakNet::SystemAddress(addr.c_str(), port)));
ss << "}";
ResponseStr<SimpleWeb::HTTP>(response, ss.str(), "application/json");
ResponseStr(*response, ss.str(), "application/json");
}
catch(out_of_range e)
{
@ -83,7 +93,7 @@ void RestServer::start()
ss << ", ";
}
ss << "}}";
ResponseStr<SimpleWeb::HTTP>(response, ss.str(), "application/json");
ResponseStr(*response, ss.str(), "application/json");
updatedCache = false;
}
*response << str;
@ -100,7 +110,7 @@ void RestServer::start()
MasterServer::SServer server;
ptreeToServer(pt, server);
auto port = pt.get<unsigned short>("port");
unsigned short port = pt.get<unsigned short>("port");
server.lastUpdate = steady_clock::now();
serverMap->insert({RakNet::SystemAddress(request->remote_endpoint_address.c_str(), port), server});
updatedCache = true;
@ -127,6 +137,7 @@ void RestServer::start()
*response << response400;
return;
}
if (request->content.size() != 0)
{
try
@ -160,14 +171,14 @@ void RestServer::start()
ss << ", \"players\": " << players;
ss << "}";
ResponseStr<SimpleWeb::HTTP>(response, ss.str(), "application/json");
ResponseStr(*response, ss.str(), "application/json");
};
httpServer.default_resource["GET"]=[](auto response, auto /*request*/) {
*response << response400;
};
thr = thread([this](){httpServer.start();});
httpServer.start();
}
void RestServer::cacheUpdated()
@ -178,6 +189,4 @@ void RestServer::cacheUpdated()
void RestServer::stop()
{
httpServer.stop();
if(thr.joinable())
thr.join();
}

View file

@ -24,7 +24,6 @@ private:
HttpServer httpServer;
MasterServer::ServerMap *serverMap;
bool updatedCache = true;
std::thread thr;
};

View file

@ -1,25 +0,0 @@
//
// Created by koncord on 04.09.17.
//
#pragma once
#include <string>
#include "SimpleWeb/base_server.hpp"
static std::string response201 = "HTTP/1.1 201 Created\r\nContent-Length: 7\r\n\r\nCreated";
static std::string response202 = "HTTP/1.1 202 Accepted\r\nContent-Length: 8\r\n\r\nAccepted";
static std::string response400 = "HTTP/1.1 400 Bad Request\r\nContent-Length: 11\r\n\r\nbad request";
static std::string response403 = "HTTP/1.1 403 Forbidden\r\nContent-Length: 9\r\n\r\nForbidden";
static std::string response500 = "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 21\r\n\r\nInternal Server Error";
template <class Protocol>
inline void ResponseStr(std::shared_ptr<typename SimpleWeb::ServerBase<Protocol>::Response> response,
std::string content, std::string type = "", std::string code = "200 OK")
{
*response << "HTTP/1.1 " << code << "\r\n";
if (!type.empty())
*response << "Content-Type: " << type <<"\r\n";
*response << "Content-Length: " << content.length() << "\r\n\r\n" << content;
}

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014-2016 Ole Christian Eidheim
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,137 +1,72 @@
#pragma once
#ifndef BASE_SERVER_HPP
#define BASE_SERVER_HPP
#include "utility.hpp"
#include <condition_variable>
#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
#include <map>
#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>
#include <map>
#include <sstream>
#include <thread>
#include <unordered_set>
#include <regex>
#ifdef USE_STANDALONE_ASIO
#include <asio.hpp>
#include <asio/steady_timer.hpp>
namespace SimpleWeb {
using error_code = std::error_code;
using errc = std::errc;
namespace make_error_code = std;
} // namespace SimpleWeb
#else
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
namespace SimpleWeb {
namespace asio = boost::asio;
using error_code = boost::system::error_code;
namespace errc = boost::system::errc;
namespace make_error_code = boost::system::errc;
} // namespace SimpleWeb
#ifndef CASE_INSENSITIVE_EQUALS_AND_HASH
#define CASE_INSENSITIVE_EQUALS_AND_HASH
//Based on http://www.boost.org/doc/libs/1_60_0/doc/html/unordered/hash_equality.html
struct case_insensitive_equals
{
bool operator()(const std::string &key1, const std::string &key2) const
{
return boost::algorithm::iequals(key1, key2);
}
};
struct case_insensitive_hash
{
size_t operator()(const std::string &key) const
{
std::size_t seed = 0;
for (auto &c: key)
boost::hash_combine(seed, std::tolower(c));
return seed;
}
};
#endif
namespace SimpleWeb {
template <class socket_type>
namespace SimpleWeb
{
template<class socket_type>
class Server;
template <class socket_type>
class ServerBase {
protected:
class Session;
template<class socket_type>
class ServerBase
{
public:
class Response : public std::enable_shared_from_this<Response>, public std::ostream {
virtual ~ServerBase()
{}
class Response : public std::ostream
{
friend class ServerBase<socket_type>;
friend class Server<socket_type>;
asio::streambuf streambuf;
boost::asio::streambuf streambuf;
std::shared_ptr<Session> session;
long timeout_content;
std::shared_ptr<socket_type> socket;
Response(std::shared_ptr<Session> session, long timeout_content) noexcept : std::ostream(&streambuf), session(std::move(session)), timeout_content(timeout_content) {}
template <typename size_type>
void write_header(const CaseInsensitiveMultimap &header, size_type size) {
bool content_length_written = false;
bool chunked_transfer_encoding = false;
for(auto &field : header) {
if(!content_length_written && case_insensitive_equal(field.first, "content-length"))
content_length_written = true;
else if(!chunked_transfer_encoding && case_insensitive_equal(field.first, "transfer-encoding") && case_insensitive_equal(field.second, "chunked"))
chunked_transfer_encoding = true;
*this << field.first << ": " << field.second << "\r\n";
}
if(!content_length_written && !chunked_transfer_encoding && !close_connection_after_response)
*this << "Content-Length: " << size << "\r\n\r\n";
else
*this << "\r\n";
}
Response(const std::shared_ptr<socket_type> &socket) : std::ostream(&streambuf), socket(socket)
{}
public:
size_t size() noexcept {
size_t size()
{
return streambuf.size();
}
/// Use this function if you need to recursively send parts of a longer message
void send(const std::function<void(const error_code &)> &callback = nullptr) noexcept {
session->connection->set_timeout(timeout_content);
auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write
asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, size_t /*bytes_transferred*/) {
self->session->connection->cancel_timeout();
auto lock = self->session->connection->handler_runner->continue_lock();
if(!lock)
return;
if(callback)
callback(ec);
});
}
/// Write directly to stream buffer using std::ostream::write
void write(const char_type *ptr, std::streamsize n) {
std::ostream::write(ptr, n);
}
/// Convenience function for writing status line, potential header fields, and empty content
void write(StatusCode status_code = StatusCode::success_ok, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
write_header(header, 0);
}
/// Convenience function for writing status line, header fields, and content
void write(StatusCode status_code, const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
write_header(header, content.size());
if(!content.empty())
*this << content;
}
/// Convenience function for writing status line, header fields, and content
void write(StatusCode status_code, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
content.seekg(0, std::ios::end);
auto size = content.tellg();
content.seekg(0, std::ios::beg);
write_header(header, size);
if(size)
*this << content.rdbuf();
}
/// Convenience function for writing success status line, header fields, and content
void write(const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
write(StatusCode::success_ok, content, header);
}
/// Convenience function for writing success status line, header fields, and content
void write(std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
write(StatusCode::success_ok, content, header);
}
/// Convenience function for writing success status line, and header fields
void write(const CaseInsensitiveMultimap &header) {
write(StatusCode::success_ok, std::string(), header);
}
/// If true, force server to close the connection after the response have been sent.
///
/// This is useful when implementing a HTTP/1.0-server sending content
@ -139,399 +74,438 @@ namespace SimpleWeb {
bool close_connection_after_response = false;
};
class Content : public std::istream {
class Content : public std::istream
{
friend class ServerBase<socket_type>;
public:
size_t size() noexcept {
size_t size()
{
return streambuf.size();
}
/// Convenience function to return std::string. The stream buffer is consumed.
std::string string() noexcept {
try {
std::stringstream ss;
ss << rdbuf();
return ss.str();
}
catch(...) {
return std::string();
}
std::string string()
{
std::stringstream ss;
ss << rdbuf();
return ss.str();
}
private:
asio::streambuf &streambuf;
Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {}
boost::asio::streambuf &streambuf;
Content(boost::asio::streambuf &streambuf) : std::istream(&streambuf), streambuf(streambuf)
{}
};
class Request {
class Request
{
friend class ServerBase<socket_type>;
friend class Server<socket_type>;
friend class Session;
public:
std::string method, path, query_string, http_version;
std::string method, path, http_version;
Content content;
CaseInsensitiveMultimap header;
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> header;
std::smatch path_match;
std::string remote_endpoint_address;
unsigned short remote_endpoint_port;
/// Returns query keys with percent-decoded values.
CaseInsensitiveMultimap parse_query_string() noexcept {
return SimpleWeb::QueryString::parse(query_string);
}
private:
asio::streambuf streambuf;
Request(const socket_type &socket) : content(streambuf)
{
try
{
remote_endpoint_address = socket.lowest_layer().remote_endpoint().address().to_string();
remote_endpoint_port = socket.lowest_layer().remote_endpoint().port();
}
catch (...)
{}
}
Request(const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
: content(streambuf), remote_endpoint_address(remote_endpoint_address), remote_endpoint_port(remote_endpoint_port) {}
boost::asio::streambuf streambuf;
};
protected:
class Connection : public std::enable_shared_from_this<Connection> {
public:
template <typename... Args>
Connection(std::shared_ptr<ScopeRunner> handler_runner, Args &&... args) noexcept : handler_runner(std::move(handler_runner)), socket(new socket_type(std::forward<Args>(args)...)) {}
std::shared_ptr<ScopeRunner> handler_runner;
std::unique_ptr<socket_type> socket; // Socket must be unique_ptr since asio::ssl::stream<asio::ip::tcp::socket> is not movable
std::mutex socket_close_mutex;
std::unique_ptr<asio::steady_timer> timer;
void close() noexcept {
error_code ec;
std::unique_lock<std::mutex> lock(socket_close_mutex); // The following operations seems to be needed to run sequentially
socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec);
socket->lowest_layer().close(ec);
}
void set_timeout(long seconds) noexcept {
if(seconds == 0) {
timer = nullptr;
return;
}
timer = std::unique_ptr<asio::steady_timer>(new asio::steady_timer(socket->get_io_service()));
timer->expires_from_now(std::chrono::seconds(seconds));
auto self = this->shared_from_this();
timer->async_wait([self](const error_code &ec) {
if(!ec)
self->close();
});
}
void cancel_timeout() noexcept {
if(timer) {
error_code ec;
timer->cancel(ec);
}
}
};
class Session {
public:
Session(std::shared_ptr<Connection> connection) noexcept : connection(std::move(connection)) {
try {
auto remote_endpoint = this->connection->socket->lowest_layer().remote_endpoint();
request = std::shared_ptr<Request>(new Request(remote_endpoint.address().to_string(), remote_endpoint.port()));
}
catch(...) {
request = std::shared_ptr<Request>(new Request());
}
}
std::shared_ptr<Connection> connection;
std::shared_ptr<Request> request;
};
public:
class Config {
class Config
{
friend class ServerBase<socket_type>;
Config(unsigned short port) noexcept : port(port) {}
Config(unsigned short port) : port(port)
{}
public:
/// Port number to use. Defaults to 80 for HTTP and 443 for HTTPS.
unsigned short port;
/// If io_service is not set, number of threads that the server will use when start() is called.
/// Defaults to 1 thread.
/// Number of threads that the server will use when start() is called. Defaults to 1 thread.
size_t thread_pool_size = 1;
/// Timeout on request handling. Defaults to 5 seconds.
long timeout_request = 5;
size_t timeout_request = 5;
/// Timeout on content handling. Defaults to 300 seconds.
long timeout_content = 300;
size_t timeout_content = 300;
/// IPv4 address in dotted decimal form or IPv6 address in hexadecimal notation.
/// If empty, the address will be any address.
std::string address;
/// Set to false to avoid binding the socket to an address that is already in use. Defaults to true.
bool reuse_address = true;
};
/// Set before calling start().
///Set before calling start().
Config config;
private:
class regex_orderable : public std::regex {
class regex_orderable : public std::regex
{
std::string str;
public:
regex_orderable(const char *regex_cstr) : std::regex(regex_cstr), str(regex_cstr) {}
regex_orderable(std::string regex_str) : std::regex(regex_str), str(std::move(regex_str)) {}
bool operator<(const regex_orderable &rhs) const noexcept {
regex_orderable(const char *regex_cstr) : std::regex(regex_cstr), str(regex_cstr)
{}
regex_orderable(const std::string &regex_str) : std::regex(regex_str), str(regex_str)
{}
bool operator<(const regex_orderable &rhs) const
{
return str < rhs.str;
}
};
public:
/// Warning: do not add or remove resources after start() is called
std::map<regex_orderable, std::map<std::string, std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)>>> resource;
std::map<regex_orderable, std::map<std::string,
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
std::shared_ptr<typename ServerBase<socket_type>::Request>)>>>
resource;
std::map<std::string, std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)>> default_resource;
std::map<std::string,
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
std::shared_ptr<typename ServerBase<socket_type>::Request>)>> default_resource;
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Request>, const error_code &)> on_error;
std::function<
void(std::shared_ptr<typename ServerBase<socket_type>::Request>,
const boost::system::error_code &)>
on_error;
std::function<void(std::unique_ptr<socket_type> &, std::shared_ptr<typename ServerBase<socket_type>::Request>)> on_upgrade;
std::function<void(std::shared_ptr<socket_type> socket,
std::shared_ptr<typename ServerBase<socket_type>::Request>)> on_upgrade;
/// If you have your own asio::io_service, store its pointer here before running start().
std::shared_ptr<asio::io_service> io_service;
virtual void start()
{
if (!io_service)
io_service = std::make_shared<boost::asio::io_service>();
virtual void start() {
if(!io_service) {
io_service = std::make_shared<asio::io_service>();
internal_io_service = true;
}
if(io_service->stopped())
if (io_service->stopped())
io_service->reset();
asio::ip::tcp::endpoint endpoint;
if(config.address.size() > 0)
endpoint = asio::ip::tcp::endpoint(asio::ip::address::from_string(config.address), config.port);
boost::asio::ip::tcp::endpoint endpoint;
if (config.address.size() > 0)
endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(config.address),
config.port);
else
endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v4(), config.port);
endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), config.port);
if(!acceptor)
acceptor = std::unique_ptr<asio::ip::tcp::acceptor>(new asio::ip::tcp::acceptor(*io_service));
if (!acceptor)
acceptor = std::unique_ptr<boost::asio::ip::tcp::acceptor>(
new boost::asio::ip::tcp::acceptor(*io_service));
acceptor->open(endpoint.protocol());
acceptor->set_option(asio::socket_base::reuse_address(config.reuse_address));
acceptor->set_option(boost::asio::socket_base::reuse_address(config.reuse_address));
acceptor->bind(endpoint);
acceptor->listen();
accept();
if(internal_io_service) {
// If thread_pool_size>1, start m_io_service.run() in (thread_pool_size-1) threads for thread-pooling
threads.clear();
for(size_t c = 1; c < config.thread_pool_size; c++) {
threads.emplace_back([this]() {
this->io_service->run();
});
}
//If thread_pool_size>1, start m_io_service.run() in (thread_pool_size-1) threads for thread-pooling
threads.clear();
for (size_t c = 1; c < config.thread_pool_size; c++)
{
threads.emplace_back([this]()
{
io_service->run();
});
}
// Main thread
if(config.thread_pool_size > 0)
io_service->run();
//Main thread
if (config.thread_pool_size > 0)
io_service->run();
// Wait for the rest of the threads, if any, to finish as well
for(auto &t : threads)
t.join();
//Wait for the rest of the threads, if any, to finish as well
for (auto &t: threads)
{
t.join();
}
}
/// Stop accepting new requests, and close current connections.
void stop() noexcept {
if(acceptor) {
error_code ec;
acceptor->close(ec);
{
std::unique_lock<std::mutex> lock(*connections_mutex);
for(auto &connection : *connections)
connection->close();
connections->clear();
}
if(internal_io_service)
io_service->stop();
}
void stop()
{
acceptor->close();
if (config.thread_pool_size > 0)
io_service->stop();
}
virtual ~ServerBase() noexcept {
handler_runner->stop();
stop();
///Use this function if you need to recursively send parts of a longer message
void send(const std::shared_ptr<Response> &response,
const std::function<void(const boost::system::error_code &)> &callback = nullptr) const
{
boost::asio::async_write(*response->socket, response->streambuf, [this, response, callback]
(const boost::system::error_code &ec, size_t /*bytes_transferred*/)
{
if (callback)
callback(ec);
});
}
/// If you have your own boost::asio::io_service, store its pointer here before running start().
/// You might also want to set config.thread_pool_size to 0.
std::shared_ptr<boost::asio::io_service> io_service;
protected:
bool internal_io_service = false;
std::unique_ptr<asio::ip::tcp::acceptor> acceptor;
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
std::vector<std::thread> threads;
std::shared_ptr<std::unordered_set<Connection *>> connections;
std::shared_ptr<std::mutex> connections_mutex;
ServerBase(unsigned short port) : config(port)
{}
std::shared_ptr<ScopeRunner> handler_runner;
virtual void accept()=0;
ServerBase(unsigned short port) noexcept : config(port), connections(new std::unordered_set<Connection *>()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {}
std::shared_ptr<boost::asio::deadline_timer>
get_timeout_timer(const std::shared_ptr<socket_type> &socket, long seconds)
{
if (seconds == 0)
return nullptr;
virtual void accept() = 0;
template <typename... Args>
std::shared_ptr<Connection> create_connection(Args &&... args) noexcept {
auto connections = this->connections;
auto connections_mutex = this->connections_mutex;
auto connection = std::shared_ptr<Connection>(new Connection(handler_runner, std::forward<Args>(args)...), [connections, connections_mutex](Connection *connection) {
{
std::unique_lock<std::mutex> lock(*connections_mutex);
auto it = connections->find(connection);
if(it != connections->end())
connections->erase(it);
}
delete connection;
});
{
std::unique_lock<std::mutex> lock(*connections_mutex);
connections->emplace(connection.get());
}
return connection;
auto timer = std::make_shared<boost::asio::deadline_timer>(*io_service);
timer->expires_from_now(boost::posix_time::seconds(seconds));
timer->async_wait([socket](const boost::system::error_code &ec)
{
if (!ec)
{
boost::system::error_code ec;
socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
socket->lowest_layer().close();
}
});
return timer;
}
void read_request_and_content(const std::shared_ptr<Session> &session) {
session->connection->set_timeout(config.timeout_request);
asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
return;
if(!ec) {
// request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
// "After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
// The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
// streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
size_t num_additional_bytes = session->request->streambuf.size() - bytes_transferred;
void read_request_and_content(const std::shared_ptr<socket_type> &socket)
{
//Create new streambuf (Request::streambuf) for async_read_until()
//shared_ptr is used to pass temporary objects to the asynchronous functions
std::shared_ptr<Request> request(new Request(*socket));
if(!RequestMessage::parse(session->request->content, session->request->method, session->request->path,
session->request->query_string, session->request->http_version, session->request->header)) {
if(this->on_error)
this->on_error(session->request, make_error_code::make_error_code(errc::protocol_error));
//Set timeout on the following boost::asio::async-read or write function
auto timer = this->get_timeout_timer(socket, config.timeout_request);
boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n", [this, socket, request, timer]
(const boost::system::error_code &ec,
size_t bytes_transferred)
{
if (timer)
timer->cancel();
if (!ec)
{
//request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
//"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
//The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
//streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
size_t num_additional_bytes =
request->streambuf.size() - bytes_transferred;
if (!this->parse_request(request))
return;
}
// If content, read that as well
auto it = session->request->header.find("Content-Length");
if(it != session->request->header.end()) {
unsigned long long content_length = 0;
try {
//If content, read that as well
auto it = request->header.find("Content-Length");
if (it != request->header.end())
{
unsigned long long content_length;
try
{
content_length = stoull(it->second);
}
catch(const std::exception &e) {
if(this->on_error)
this->on_error(session->request, make_error_code::make_error_code(errc::protocol_error));
catch (const std::exception &e)
{
if (on_error)
on_error(request, boost::system::error_code(
boost::system::errc::protocol_error,
boost::system::generic_category()));
return;
}
if(content_length > num_additional_bytes) {
session->connection->set_timeout(config.timeout_content);
asio::async_read(*session->connection->socket, session->request->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
return;
if(!ec)
this->find_resource(session);
else if(this->on_error)
this->on_error(session->request, ec);
});
if (content_length > num_additional_bytes)
{
//Set timeout on the following boost::asio::async-read or write function
auto timer = this->get_timeout_timer(socket,
config.timeout_content);
boost::asio::async_read(*socket, request->streambuf,
boost::asio::transfer_exactly(
content_length -
num_additional_bytes),
[this, socket, request, timer]
(const boost::system::error_code &ec,
size_t /*bytes_transferred*/)
{
if (timer)
timer->cancel();
if (!ec)
this->find_resource(socket,
request);
else if (on_error)
on_error(request, ec);
});
}
else
this->find_resource(session);
this->find_resource(socket, request);
}
else
this->find_resource(session);
this->find_resource(socket, request);
}
else if(this->on_error)
this->on_error(session->request, ec);
else if (on_error)
on_error(request, ec);
});
}
void find_resource(const std::shared_ptr<Session> &session) {
// Upgrade connection
if(on_upgrade) {
auto it = session->request->header.find("Upgrade");
if(it != session->request->header.end()) {
// remove connection from connections
{
std::unique_lock<std::mutex> lock(*connections_mutex);
auto it = connections->find(session->connection.get());
if(it != connections->end())
connections->erase(it);
}
bool parse_request(const std::shared_ptr<Request> &request) const
{
std::string line;
getline(request->content, line);
size_t method_end;
if ((method_end = line.find(' ')) != std::string::npos)
{
size_t path_end;
if ((path_end = line.find(' ', method_end + 1)) != std::string::npos)
{
request->method = line.substr(0, method_end);
request->path = line.substr(method_end + 1, path_end - method_end - 1);
on_upgrade(session->connection->socket, session->request);
size_t protocol_end;
if ((protocol_end = line.find('/', path_end + 1)) != std::string::npos)
{
if (line.compare(path_end + 1, protocol_end - path_end - 1, "HTTP") != 0)
return false;
request->http_version = line.substr(protocol_end + 1, line.size() - protocol_end - 2);
}
else
return false;
getline(request->content, line);
size_t param_end;
while ((param_end = line.find(':')) != std::string::npos)
{
size_t value_start = param_end + 1;
if ((value_start) < line.size())
{
if (line[value_start] == ' ')
value_start++;
if (value_start < line.size())
request->header.emplace(line.substr(0, param_end),
line.substr(value_start, line.size() - value_start - 1));
}
getline(request->content, line);
}
}
else
return false;
}
else
return false;
return true;
}
void find_resource(const std::shared_ptr<socket_type> &socket, const std::shared_ptr<Request> &request)
{
//Upgrade connection
if (on_upgrade)
{
auto it = request->header.find("Upgrade");
if (it != request->header.end())
{
on_upgrade(socket, request);
return;
}
}
// Find path- and method-match, and call write_response
for(auto &regex_method : resource) {
auto it = regex_method.second.find(session->request->method);
if(it != regex_method.second.end()) {
//Find path- and method-match, and call write_response
for (auto &regex_method: resource)
{
auto it = regex_method.second.find(request->method);
if (it != regex_method.second.end())
{
std::smatch sm_res;
if(std::regex_match(session->request->path, sm_res, regex_method.first)) {
session->request->path_match = std::move(sm_res);
write_response(session, it->second);
if (std::regex_match(request->path, sm_res, regex_method.first))
{
request->path_match = std::move(sm_res);
write_response(socket, request, it->second);
return;
}
}
}
auto it = default_resource.find(session->request->method);
if(it != default_resource.end())
write_response(session, it->second);
auto it = default_resource.find(request->method);
if (it != default_resource.end())
{
write_response(socket, request, it->second);
}
}
void write_response(const std::shared_ptr<Session> &session,
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> &resource_function) {
session->connection->set_timeout(config.timeout_content);
auto response = std::shared_ptr<Response>(new Response(session, config.timeout_content), [this](Response *response_ptr) {
void write_response(const std::shared_ptr<socket_type> &socket, const std::shared_ptr<Request> &request,
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
std::shared_ptr<
typename ServerBase<socket_type>::Request>)> &resource_function)
{
//Set timeout on the following boost::asio::async-read or write function
auto timer = this->get_timeout_timer(socket, config.timeout_content);
auto response = std::shared_ptr<Response>(new Response(socket), [this, request, timer]
(Response *response_ptr)
{
auto response = std::shared_ptr<Response>(response_ptr);
response->send([this, response](const error_code &ec) {
if(!ec) {
if(response->close_connection_after_response)
this->send(response, [this, response, request, timer](
const boost::system::error_code &ec)
{
if (timer)
timer->cancel();
if (!ec)
{
if (response->close_connection_after_response)
return;
auto range = response->session->request->header.equal_range("Connection");
for(auto it = range.first; it != range.second; it++) {
if(case_insensitive_equal(it->second, "close"))
auto range = request->header.equal_range(
"Connection");
for (auto it = range.first; it != range.second; it++)
{
if (boost::iequals(it->second, "close"))
{
return;
else if(case_insensitive_equal(it->second, "keep-alive")) {
auto new_session = std::make_shared<Session>(response->session->connection);
this->read_request_and_content(new_session);
}
else if (boost::iequals(it->second, "keep-alive"))
{
this->read_request_and_content(
response->socket);
return;
}
}
if(response->session->request->http_version >= "1.1") {
auto new_session = std::make_shared<Session>(response->session->connection);
this->read_request_and_content(new_session);
return;
}
if (request->http_version >= "1.1")
this->read_request_and_content(response->socket);
}
else if(this->on_error)
this->on_error(response->session->request, ec);
else if (on_error)
on_error(request, ec);
});
});
try {
resource_function(response, session->request);
try
{
resource_function(response, request);
}
catch(const std::exception &e) {
if(on_error)
on_error(session->request, make_error_code::make_error_code(errc::operation_canceled));
catch (const std::exception &e)
{
if (on_error)
on_error(request, boost::system::error_code(boost::system::errc::operation_canceled,
boost::system::generic_category()));
return;
}
}
};
}
#endif //BASE_SERVER_HPP

View file

@ -1,42 +1,55 @@
#pragma once
/*
* https://github.com/eidheim/Simple-Web-Server/
*
* The MIT License (MIT)
* Copyright (c) 2014-2016 Ole Christian Eidheim
*/
#ifndef SERVER_HTTP_HPP
#define SERVER_HTTP_HPP
#include "base_server.hpp"
namespace SimpleWeb {
namespace SimpleWeb
{
template <class socket_type>
template<class socket_type>
class Server : public ServerBase<socket_type> {};
using HTTP = asio::ip::tcp::socket;
typedef boost::asio::ip::tcp::socket HTTP;
template <>
class Server<HTTP> : public ServerBase<HTTP> {
template<>
class Server<HTTP> : public ServerBase<HTTP>
{
public:
Server() noexcept : ServerBase<HTTP>::ServerBase(80) {}
Server() : ServerBase<HTTP>::ServerBase(80)
{}
protected:
void accept() override {
auto session = std::make_shared<Session>(create_connection(*io_service));
virtual void accept()
{
//Create new socket for this connection
//Shared_ptr is used to pass temporary objects to the asynchronous functions
auto socket = std::make_shared<HTTP>(*io_service);
acceptor->async_accept(*session->connection->socket, [this, session](const error_code &ec) {
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
return;
acceptor->async_accept(*socket, [this, socket](const boost::system::error_code &ec)
{
//Immediately start accepting a new connection (if io_service hasn't been stopped)
if (ec != boost::asio::error::operation_aborted)
accept();
// Immediately start accepting a new connection (unless io_service has been stopped)
if(ec != asio::error::operation_aborted)
this->accept();
if (!ec)
{
boost::asio::ip::tcp::no_delay option(true);
socket->set_option(option);
if(!ec) {
asio::ip::tcp::no_delay option(true);
error_code ec;
session->connection->socket->set_option(option, ec);
this->read_request_and_content(session);
this->read_request_and_content(socket);
}
else if(this->on_error)
this->on_error(session->request, ec);
else if (on_error)
on_error(std::shared_ptr<Request>(new Request(*socket)), ec);
});
}
};
} // namespace SimpleWeb
}
#endif //SERVER_HTTP_HPP

View file

@ -1,82 +1,91 @@
#pragma once
#ifndef HTTPS_SERVER_HPP
#define HTTPS_SERVER_HPP
#include "base_server.hpp"
#ifdef USE_STANDALONE_ASIO
#include <asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp>
#endif
#include <algorithm>
#include <openssl/ssl.h>
#include <algorithm>
namespace SimpleWeb {
using HTTPS = asio::ssl::stream<asio::ip::tcp::socket>;
namespace SimpleWeb
{
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> HTTPS;
template <>
class Server<HTTPS> : public ServerBase<HTTPS> {
template<>
class Server<HTTPS> : public ServerBase<HTTPS>
{
std::string session_id_context;
bool set_session_id_context = false;
public:
Server(const std::string &cert_file, const std::string &private_key_file, const std::string &verify_file = std::string())
: ServerBase<HTTPS>::ServerBase(443), context(asio::ssl::context::tlsv12) {
Server(const std::string &cert_file, const std::string &private_key_file,
const std::string &verify_file = std::string()) : ServerBase<HTTPS>::ServerBase(443),
context(boost::asio::ssl::context::tlsv12)
{
context.use_certificate_chain_file(cert_file);
context.use_private_key_file(private_key_file, asio::ssl::context::pem);
context.use_private_key_file(private_key_file, boost::asio::ssl::context::pem);
if(verify_file.size() > 0) {
if (verify_file.size() > 0)
{
context.load_verify_file(verify_file);
context.set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert | asio::ssl::verify_client_once);
context.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert |
boost::asio::ssl::verify_client_once);
set_session_id_context = true;
}
}
void start() override {
if(set_session_id_context) {
void start()
{
if (set_session_id_context)
{
// Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH
session_id_context = std::to_string(config.port) + ':';
session_id_context.append(config.address.rbegin(), config.address.rend());
SSL_CTX_set_session_id_context(context.native_handle(), reinterpret_cast<const unsigned char *>(session_id_context.data()),
std::min<size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH));
SSL_CTX_set_session_id_context(context.native_handle(),
reinterpret_cast<const unsigned char *>(session_id_context.data()),
std::min<size_t>(session_id_context.size(),
SSL_MAX_SSL_SESSION_ID_LENGTH));
}
ServerBase::start();
}
protected:
asio::ssl::context context;
boost::asio::ssl::context context;
void accept() override {
auto session = std::make_shared<Session>(create_connection(*io_service, context));
virtual void accept()
{
//Create new socket for this connection
//Shared_ptr is used to pass temporary objects to the asynchronous functions
auto socket = std::make_shared<HTTPS>(*io_service, context);
acceptor->async_accept(session->connection->socket->lowest_layer(), [this, session](const error_code &ec) {
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
return;
acceptor->async_accept((*socket).lowest_layer(), [this, socket](const boost::system::error_code &ec)
{
//Immediately start accepting a new connection (if io_service hasn't been stopped)
if (ec != boost::asio::error::operation_aborted)
accept();
if(ec != asio::error::operation_aborted)
this->accept();
if(!ec) {
asio::ip::tcp::no_delay option(true);
error_code ec;
session->connection->socket->lowest_layer().set_option(option, ec);
if (!ec)
{
boost::asio::ip::tcp::no_delay option(true);
socket->lowest_layer().set_option(option);
session->connection->set_timeout(config.timeout_request);
session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code &ec) {
session->connection->cancel_timeout();
auto lock = session->connection->handler_runner->continue_lock();
if(!lock)
return;
if(!ec)
this->read_request_and_content(session);
else if(this->on_error)
this->on_error(session->request, ec);
//Set timeout on the following boost::asio::ssl::stream::async_handshake
auto timer = get_timeout_timer(socket, config.timeout_request);
socket->async_handshake(boost::asio::ssl::stream_base::server, [this, socket, timer]
(const boost::system::error_code &ec)
{
if (timer)
timer->cancel();
if (!ec)
read_request_and_content(socket);
else if (on_error)
on_error(std::shared_ptr<Request>(new Request(*socket)), ec);
});
}
else if(this->on_error)
this->on_error(session->request, ec);
else if (on_error)
on_error(std::shared_ptr<Request>(new Request(*socket)), ec);
});
}
};
} // namespace SimpleWeb
}
#endif //HTTPS_SERVER_HPP

View file

@ -1,154 +0,0 @@
#pragma once
#include <string>
#include <vector>
namespace SimpleWeb {
enum class StatusCode {
unknown = 0,
information_continue = 100,
information_switching_protocols,
information_processing,
success_ok = 200,
success_created,
success_accepted,
success_non_authoritative_information,
success_no_content,
success_reset_content,
success_partial_content,
success_multi_status,
success_already_reported,
success_im_used = 226,
redirection_multiple_choices = 300,
redirection_moved_permanently,
redirection_found,
redirection_see_other,
redirection_not_modified,
redirection_use_proxy,
redirection_switch_proxy,
redirection_temporary_redirect,
redirection_permanent_redirect,
client_error_bad_request = 400,
client_error_unauthorized,
client_error_payment_required,
client_error_forbidden,
client_error_not_found,
client_error_method_not_allowed,
client_error_not_acceptable,
client_error_proxy_authentication_required,
client_error_request_timeout,
client_error_conflict,
client_error_gone,
client_error_length_required,
client_error_precondition_failed,
client_error_payload_too_large,
client_error_uri_too_long,
client_error_unsupported_media_type,
client_error_range_not_satisfiable,
client_error_expectation_failed,
client_error_im_a_teapot,
client_error_misdirection_required = 421,
client_error_unprocessable_entity,
client_error_locked,
client_error_failed_dependency,
client_error_upgrade_required = 426,
client_error_precondition_required = 428,
client_error_too_many_requests,
client_error_request_header_fields_too_large = 431,
client_error_unavailable_for_legal_reasons = 451,
server_error_internal_server_error = 500,
server_error_not_implemented,
server_error_bad_gateway,
server_error_service_unavailable,
server_error_gateway_timeout,
server_error_http_version_not_supported,
server_error_variant_also_negotiates,
server_error_insufficient_storage,
server_error_loop_detected,
server_error_not_extended = 510,
server_error_network_authentication_required
};
const static std::vector<std::pair<StatusCode, std::string>> &status_codes() noexcept {
const static std::vector<std::pair<StatusCode, std::string>> status_codes = {
{StatusCode::unknown, ""},
{StatusCode::information_continue, "100 Continue"},
{StatusCode::information_switching_protocols, "101 Switching Protocols"},
{StatusCode::information_processing, "102 Processing"},
{StatusCode::success_ok, "200 OK"},
{StatusCode::success_created, "201 Created"},
{StatusCode::success_accepted, "202 Accepted"},
{StatusCode::success_non_authoritative_information, "203 Non-Authoritative Information"},
{StatusCode::success_no_content, "204 No Content"},
{StatusCode::success_reset_content, "205 Reset Content"},
{StatusCode::success_partial_content, "206 Partial Content"},
{StatusCode::success_multi_status, "207 Multi-Status"},
{StatusCode::success_already_reported, "208 Already Reported"},
{StatusCode::success_im_used, "226 IM Used"},
{StatusCode::redirection_multiple_choices, "300 Multiple Choices"},
{StatusCode::redirection_moved_permanently, "301 Moved Permanently"},
{StatusCode::redirection_found, "302 Found"},
{StatusCode::redirection_see_other, "303 See Other"},
{StatusCode::redirection_not_modified, "304 Not Modified"},
{StatusCode::redirection_use_proxy, "305 Use Proxy"},
{StatusCode::redirection_switch_proxy, "306 Switch Proxy"},
{StatusCode::redirection_temporary_redirect, "307 Temporary Redirect"},
{StatusCode::redirection_permanent_redirect, "308 Permanent Redirect"},
{StatusCode::client_error_bad_request, "400 Bad Request"},
{StatusCode::client_error_unauthorized, "401 Unauthorized"},
{StatusCode::client_error_payment_required, "402 Payment Required"},
{StatusCode::client_error_forbidden, "403 Forbidden"},
{StatusCode::client_error_not_found, "404 Not Found"},
{StatusCode::client_error_method_not_allowed, "405 Method Not Allowed"},
{StatusCode::client_error_not_acceptable, "406 Not Acceptable"},
{StatusCode::client_error_proxy_authentication_required, "407 Proxy Authentication Required"},
{StatusCode::client_error_request_timeout, "408 Request Timeout"},
{StatusCode::client_error_conflict, "409 Conflict"},
{StatusCode::client_error_gone, "410 Gone"},
{StatusCode::client_error_length_required, "411 Length Required"},
{StatusCode::client_error_precondition_failed, "412 Precondition Failed"},
{StatusCode::client_error_payload_too_large, "413 Payload Too Large"},
{StatusCode::client_error_uri_too_long, "414 URI Too Long"},
{StatusCode::client_error_unsupported_media_type, "415 Unsupported Media Type"},
{StatusCode::client_error_range_not_satisfiable, "416 Range Not Satisfiable"},
{StatusCode::client_error_expectation_failed, "417 Expectation Failed"},
{StatusCode::client_error_im_a_teapot, "418 I'm a teapot"},
{StatusCode::client_error_misdirection_required, "421 Misdirected Request"},
{StatusCode::client_error_unprocessable_entity, "422 Unprocessable Entity"},
{StatusCode::client_error_locked, "423 Locked"},
{StatusCode::client_error_failed_dependency, "424 Failed Dependency"},
{StatusCode::client_error_upgrade_required, "426 Upgrade Required"},
{StatusCode::client_error_precondition_required, "428 Precondition Required"},
{StatusCode::client_error_too_many_requests, "429 Too Many Requests"},
{StatusCode::client_error_request_header_fields_too_large, "431 Request Header Fields Too Large"},
{StatusCode::client_error_unavailable_for_legal_reasons, "451 Unavailable For Legal Reasons"},
{StatusCode::server_error_internal_server_error, "500 Internal Server Error"},
{StatusCode::server_error_not_implemented, "501 Not Implemented"},
{StatusCode::server_error_bad_gateway, "502 Bad Gateway"},
{StatusCode::server_error_service_unavailable, "503 Service Unavailable"},
{StatusCode::server_error_gateway_timeout, "504 Gateway Timeout"},
{StatusCode::server_error_http_version_not_supported, "505 HTTP Version Not Supported"},
{StatusCode::server_error_variant_also_negotiates, "506 Variant Also Negotiates"},
{StatusCode::server_error_insufficient_storage, "507 Insufficient Storage"},
{StatusCode::server_error_loop_detected, "508 Loop Detected"},
{StatusCode::server_error_not_extended, "510 Not Extended"},
{StatusCode::server_error_network_authentication_required, "511 Network Authentication Required"}};
return status_codes;
}
inline StatusCode status_code(const std::string &status_code_str) noexcept {
for(auto &status_code : status_codes()) {
if(status_code.second == status_code_str)
return status_code.first;
}
return StatusCode::unknown;
}
inline const std::string &status_code(StatusCode status_code_enum) noexcept {
for(auto &status_code : status_codes()) {
if(status_code.first == status_code_enum)
return status_code.second;
}
return status_codes()[0].second;
}
} // namespace SimpleWeb

View file

@ -1,340 +0,0 @@
#pragma once
#include "status_code.hpp"
#include <atomic>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
namespace SimpleWeb {
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept {
return str1.size() == str2.size() &&
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
return tolower(a) == tolower(b);
});
}
class CaseInsensitiveEqual {
public:
bool operator()(const std::string &str1, const std::string &str2) const noexcept {
return case_insensitive_equal(str1, str2);
}
};
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
class CaseInsensitiveHash {
public:
size_t operator()(const std::string &str) const noexcept {
size_t h = 0;
std::hash<int> hash;
for(auto c : str)
h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
return h;
}
};
using CaseInsensitiveMultimap = std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual>;
/// Percent encoding and decoding
class Percent {
public:
/// Returns percent-encoded string
static std::string encode(const std::string &value) noexcept {
static auto hex_chars = "0123456789ABCDEF";
std::string result;
result.reserve(value.size()); // Minimum size of result
for(auto &chr : value) {
if(chr == ' ')
result += '+';
else if(chr == '!' || chr == '#' || chr == '$' || (chr >= '&' && chr <= ',') || (chr >= '/' && chr <= ';') || chr == '=' || chr == '?' || chr == '@' || chr == '[' || chr == ']')
result += std::string("%") + hex_chars[chr >> 4] + hex_chars[chr & 15];
else
result += chr;
}
return result;
}
/// Returns percent-decoded string
static std::string decode(const std::string &value) noexcept {
std::string result;
result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result
for(size_t i = 0; i < value.size(); ++i) {
auto &chr = value[i];
if(chr == '%' && i + 2 < value.size()) {
auto hex = value.substr(i + 1, 2);
auto decoded_chr = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
result += decoded_chr;
i += 2;
}
else if(chr == '+')
result += ' ';
else
result += chr;
}
return result;
}
};
/// Query string creation and parsing
class QueryString {
public:
/// Returns query string created from given field names and values
static std::string create(const CaseInsensitiveMultimap &fields) noexcept {
std::string result;
bool first = true;
for(auto &field : fields) {
result += (!first ? "&" : "") + field.first + '=' + Percent::encode(field.second);
first = false;
}
return result;
}
/// Returns query keys with percent-decoded values.
static CaseInsensitiveMultimap parse(const std::string &query_string) noexcept {
CaseInsensitiveMultimap result;
if(query_string.empty())
return result;
size_t name_pos = 0;
auto name_end_pos = std::string::npos;
auto value_pos = std::string::npos;
for(size_t c = 0; c < query_string.size(); ++c) {
if(query_string[c] == '&') {
auto name = query_string.substr(name_pos, (name_end_pos == std::string::npos ? c : name_end_pos) - name_pos);
if(!name.empty()) {
auto value = value_pos == std::string::npos ? std::string() : query_string.substr(value_pos, c - value_pos);
result.emplace(std::move(name), Percent::decode(value));
}
name_pos = c + 1;
name_end_pos = std::string::npos;
value_pos = std::string::npos;
}
else if(query_string[c] == '=') {
name_end_pos = c;
value_pos = c + 1;
}
}
if(name_pos < query_string.size()) {
auto name = query_string.substr(name_pos, name_end_pos - name_pos);
if(!name.empty()) {
auto value = value_pos >= query_string.size() ? std::string() : query_string.substr(value_pos);
result.emplace(std::move(name), Percent::decode(value));
}
}
return result;
}
};
class HttpHeader {
public:
/// Parse header fields
static CaseInsensitiveMultimap parse(std::istream &stream) noexcept {
CaseInsensitiveMultimap result;
std::string line;
getline(stream, line);
size_t param_end;
while((param_end = line.find(':')) != std::string::npos) {
size_t value_start = param_end + 1;
if(value_start < line.size()) {
if(line[value_start] == ' ')
value_start++;
if(value_start < line.size())
result.emplace(line.substr(0, param_end), line.substr(value_start, line.size() - value_start - 1));
}
getline(stream, line);
}
return result;
}
};
class RequestMessage {
public:
/// Parse request line and header fields
static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) noexcept {
header.clear();
std::string line;
getline(stream, line);
size_t method_end;
if((method_end = line.find(' ')) != std::string::npos) {
method = line.substr(0, method_end);
size_t query_start = std::string::npos;
size_t path_and_query_string_end = std::string::npos;
for(size_t i = method_end + 1; i < line.size(); ++i) {
if(line[i] == '?' && (i + 1) < line.size())
query_start = i + 1;
else if(line[i] == ' ') {
path_and_query_string_end = i;
break;
}
}
if(path_and_query_string_end != std::string::npos) {
if(query_start != std::string::npos) {
path = line.substr(method_end + 1, query_start - method_end - 2);
query_string = line.substr(query_start, path_and_query_string_end - query_start);
}
else
path = line.substr(method_end + 1, path_and_query_string_end - method_end - 1);
size_t protocol_end;
if((protocol_end = line.find('/', path_and_query_string_end + 1)) != std::string::npos) {
if(line.compare(path_and_query_string_end + 1, protocol_end - path_and_query_string_end - 1, "HTTP") != 0)
return false;
version = line.substr(protocol_end + 1, line.size() - protocol_end - 2);
}
else
return false;
header = HttpHeader::parse(stream);
}
else
return false;
}
else
return false;
return true;
}
};
class ResponseMessage {
public:
/// Parse status line and header fields
static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) noexcept {
header.clear();
std::string line;
getline(stream, line);
size_t version_end = line.find(' ');
if(version_end != std::string::npos) {
if(5 < line.size())
version = line.substr(5, version_end - 5);
else
return false;
if((version_end + 1) < line.size())
status_code = line.substr(version_end + 1, line.size() - (version_end + 1) - 1);
else
return false;
header = HttpHeader::parse(stream);
}
else
return false;
return true;
}
};
class ContentDisposition {
public:
/// Can be used to parse the Content-Disposition header field value when
/// clients are posting requests with enctype="multipart/form-data"
static CaseInsensitiveMultimap parse(const std::string &line) {
CaseInsensitiveMultimap result;
size_t para_start_pos = 0;
size_t para_end_pos = std::string::npos;
size_t value_start_pos = std::string::npos;
for(size_t c = 0; c < line.size(); ++c) {
if(para_start_pos != std::string::npos) {
if(para_end_pos == std::string::npos) {
if(line[c] == ';') {
result.emplace(line.substr(para_start_pos, c - para_start_pos), std::string());
para_start_pos = std::string::npos;
}
else if(line[c] == '=')
para_end_pos = c;
}
else {
if(value_start_pos == std::string::npos) {
if(line[c] == '"' && c + 1 < line.size())
value_start_pos = c + 1;
}
else if(line[c] == '"') {
result.emplace(line.substr(para_start_pos, para_end_pos - para_start_pos), line.substr(value_start_pos, c - value_start_pos));
para_start_pos = std::string::npos;
para_end_pos = std::string::npos;
value_start_pos = std::string::npos;
}
}
}
else if(line[c] != ' ' && line[c] != ';')
para_start_pos = c;
}
if(para_start_pos != std::string::npos && para_end_pos == std::string::npos)
result.emplace(line.substr(para_start_pos), std::string());
return result;
}
};
} // namespace SimpleWeb
#ifdef __SSE2__
#include <emmintrin.h>
namespace SimpleWeb {
inline void spin_loop_pause() noexcept { _mm_pause(); }
} // namespace SimpleWeb
// TODO: need verification that the following checks are correct:
#elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86))
#include <intrin.h>
namespace SimpleWeb {
inline void spin_loop_pause() noexcept { _mm_pause(); }
} // namespace SimpleWeb
#else
namespace SimpleWeb {
inline void spin_loop_pause() noexcept {}
} // namespace SimpleWeb
#endif
namespace SimpleWeb {
/// Makes it possible to for instance cancel Asio handlers without stopping asio::io_service
class ScopeRunner {
/// Scope count that is set to -1 if scopes are to be canceled
std::atomic<long> count;
public:
class SharedLock {
friend class ScopeRunner;
std::atomic<long> &count;
SharedLock(std::atomic<long> &count) noexcept : count(count) {}
SharedLock &operator=(const SharedLock &) = delete;
SharedLock(const SharedLock &) = delete;
public:
~SharedLock() noexcept {
count.fetch_sub(1);
}
};
ScopeRunner() noexcept : count(0) {}
/// Returns nullptr if scope should be exited, or a shared lock otherwise
std::unique_ptr<SharedLock> continue_lock() noexcept {
long expected = count;
while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1))
spin_loop_pause();
if(expected < 0)
return nullptr;
else
return std::unique_ptr<SharedLock>(new SharedLock(count));
}
/// Blocks until all shared locks are released, then prevents future shared locks
void stop() noexcept {
long expected = 0;
while(!count.compare_exchange_weak(expected, -1)) {
if(expected < 0)
return;
expected = 0;
spin_loop_pause();
}
}
};
} // namespace SimpleWeb

View file

@ -1,74 +1,36 @@
#include <iostream>
#include <Kbhit.h>
#include <RakSleep.h>
#include <sol.hpp>
#include "MasterServer.hpp"
#include "RestServer.hpp"
#include "AdminRest.hpp"
using namespace RakNet;
using namespace std;
unique_ptr<RestServer> restServer;
shared_ptr<MasterServer> masterServer;
unique_ptr<AdminRest> restAdminServer;
unique_ptr<MasterServer> masterServer;
bool run = true;
int main(int argc, char* argv[])
int main()
{
if (argc != 2)
return 1;
string luaScript(argv[1]);
masterServer = make_shared<MasterServer>(luaScript);
masterServer->luaStuff([](sol::state &state)
{
sol::table config = state["config"];
sol::object restPort = config["restPort"];
if (restPort.get_type() != sol::type::number)
throw runtime_error("config.restPort is not correct");
restServer = make_unique<RestServer>(restPort.as<unsigned short>(), masterServer->GetServers());
sol::object restAdminCert = config["restAdminCert"];
if (restAdminCert.get_type() != sol::type::string)
throw runtime_error("config.restAdminCert is not correct");
sol::object restAdminKey = config["restAdminKey"];
if (restAdminKey.get_type() != sol::type::string)
throw runtime_error("config.restAdminKey is not correct");
sol::object restAdminVerifyFile = config["restAdminVerifyFile"];
if (restAdminVerifyFile.get_type() != sol::type::string)
throw runtime_error("config.restAdminVerifyFile is not correct");
sol::object restAdminPort = config["restAdminPort"];
if (restAdminPort.get_type() != sol::type::number)
throw runtime_error("config.restAdminPort is not correct");
restAdminServer = make_unique<AdminRest>(restAdminCert.as<string>(), restAdminKey.as<string>(),
restAdminVerifyFile.as<string>(), restAdminPort.as<unsigned short>(), masterServer);
});
masterServer.reset(new MasterServer(2000, 25560));
restServer.reset(new RestServer(8080, masterServer->GetServers()));
auto onExit = [](int /*sig*/){
restServer->stop();
restAdminServer->stop();
masterServer->luaStuff([](sol::state &state) {
sol::protected_function func = state["OnExit"];
if (func.valid())
func.call();
});
masterServer->Stop(false);
masterServer->Wait();
run = false;
};
signal(SIGINT, onExit);
signal(SIGTERM, onExit);
masterServer->Start();
restServer->start();
restAdminServer->start();
thread server_thread([]() { restServer->start(); });
server_thread.join();
masterServer->Wait();
return 0;

View file

@ -874,7 +874,6 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
{
std::vector<std::pair<std::time_t, boost::filesystem::path>> contentFiles;
std::string baseGameFile("Game Files:GameFile");
std::string gameFile("");
std::time_t defaultTime = 0;
ToUTF8::Utf8Encoder encoder(mEncoding);
@ -890,7 +889,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
multistrmap::const_iterator it = ini.begin();
for (int i=0; it != ini.end(); i++)
{
gameFile = baseGameFile;
std::string gameFile = baseGameFile;
gameFile.append(std::to_string(i));
it = ini.find(gameFile);

View file

@ -5,6 +5,9 @@
#include <QLocalSocket>
#include <QMessageBox>
#include <components/crashcatcher/crashcatcher.hpp>
#include <components/fallback/validate.hpp>
#include <components/nifosg/nifloader.hpp>
@ -18,12 +21,16 @@
using namespace Fallback;
CS::Editor::Editor ()
CS::Editor::Editor (int argc, char **argv)
: mSettingsState (mCfgMgr), mDocumentManager (mCfgMgr),
mViewManager (mDocumentManager), mPid(""),
mLock(), mMerge (mDocumentManager),
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
{
// install the crash handler as soon as possible. note that the log path
// does not depend on config being read.
crashCatcherInstall(argc, argv, (mCfgMgr.getLogPath() / "openmw-cs-crash.log").string());
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
setupDataFiles (config.first);

View file

@ -66,7 +66,7 @@ namespace CS
public:
Editor ();
Editor (int argc, char **argv);
~Editor ();
bool makeIPCServer();

View file

@ -8,8 +8,9 @@
#include <QIcon>
#include <QMetaType>
#include "model/doc/messages.hpp"
#include <components/misc/debugging.hpp>
#include "model/doc/messages.hpp"
#include "model/world/universalid.hpp"
#ifdef Q_OS_MAC
@ -41,45 +42,43 @@ class Application : public QApplication
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
};
int main(int argc, char *argv[])
int runApplication(int argc, char *argv[])
{
#ifdef Q_OS_MAC
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
#endif
#ifdef Q_OS_MAC
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
#endif
try
// To allow background thread drawing in OSG
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
Q_INIT_RESOURCE (resources);
qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
Application application (argc, argv);
#ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath());
QDir::setCurrent(dir.absolutePath());
#endif
application.setWindowIcon (QIcon (":./openmw-cs.png"));
CS::Editor editor(argc, argv);
if(!editor.makeIPCServer())
{
// To allow background thread drawing in OSG
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
Q_INIT_RESOURCE (resources);
qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
Application application (argc, argv);
#ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath());
QDir::setCurrent(dir.absolutePath());
#endif
application.setWindowIcon (QIcon (":./openmw-cs.png"));
CS::Editor editor;
if(!editor.makeIPCServer())
{
editor.connectToIPCServer();
return 0;
}
return editor.run();
}
catch (std::exception& e)
{
std::cerr << "ERROR: " << e.what() << std::endl;
editor.connectToIPCServer();
return 0;
}
return editor.run();
}
int main(int argc, char *argv[])
{
return wrapApplication(&runApplication, argc, argv, "/openmw-cs.log");
}

View file

@ -320,12 +320,13 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (&mTools, SIGNAL (done (int, bool)), this, SIGNAL (operationDone (int, bool)));
connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone2 (int, bool)));
connect (&mTools, SIGNAL (mergeDone (CSMDoc::Document*)),
this, SIGNAL (mergeDone (CSMDoc::Document*)));
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone2 (int, bool)));
connect (
&mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
@ -437,7 +438,7 @@ void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
std::cout << message.mMessage << std::endl;
}
void CSMDoc::Document::operationDone (int type, bool failed)
void CSMDoc::Document::operationDone2 (int type, bool failed)
{
if (type==CSMDoc::State_Saving && !failed)
mDirty = false;

View file

@ -168,13 +168,15 @@ namespace CSMDoc
/// document. This signal must be handled to avoid a leak.
void mergeDone (CSMDoc::Document *document);
void operationDone (int type, bool failed);
private slots:
void modificationStateChanged (bool clean);
void reportMessage (const CSMDoc::Message& message, int type);
void operationDone (int type, bool failed);
void operationDone2 (int type, bool failed);
void runStateChanged();

View file

@ -123,6 +123,7 @@ void CSMPrefs::State::declare()
declareEnum ("double-s", "Shift Double Click", actionRemove).addValues (reportValues);
declareEnum ("double-c", "Control Double Click", actionEditAndRemove).addValues (reportValues);
declareEnum ("double-sc", "Shift Control Double Click", actionNone).addValues (reportValues);
declareBool("ignore-base-records", "Ignore base records in verifier", false);
declareCategory ("Search & Replace");
declareInt ("char-before", "Characters before search string", 10).
@ -200,6 +201,9 @@ void CSMPrefs::State::declare()
declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
declareCategory ("Rendering");
declareInt ("framerate-limit", "FPS limit", 60).
setTooltip("Framerate limit in 3D preview windows. Zero value means \"unlimited\".").
setRange(0, 10000);
declareInt ("camera-fov", "Camera FOV", 90).setRange(10, 170);
declareBool ("camera-ortho", "Orthographic projection for camera", false);
declareInt ("camera-ortho-size", "Orthographic projection size parameter", 100).

View file

@ -5,14 +5,20 @@
#include <components/esm/loadbsgn.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection<ESM::BirthSign>& birthsigns)
: mBirthsigns (birthsigns)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::BirthsignCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mBirthsigns.getSize();
}
@ -20,7 +26,8 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag
{
const CSMWorld::Record<ESM::BirthSign>& record = mBirthsigns.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::BirthSign& birthsign = record.get();

View file

@ -13,6 +13,7 @@ namespace CSMTools
class BirthsignCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::BirthSign>& mBirthsigns;
bool mIgnoreBaseRecords;
public:

View file

@ -1,5 +1,7 @@
#include "bodypartcheck.hpp"
#include "../prefs/state.hpp"
CSMTools::BodyPartCheckStage::BodyPartCheckStage(
const CSMWorld::IdCollection<ESM::BodyPart> &bodyParts,
const CSMWorld::Resources &meshes,
@ -7,10 +9,14 @@ CSMTools::BodyPartCheckStage::BodyPartCheckStage(
mBodyParts(bodyParts),
mMeshes(meshes),
mRaces(races)
{ }
{
mIgnoreBaseRecords = false;
}
int CSMTools::BodyPartCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mBodyParts.getSize();
}
@ -18,7 +24,8 @@ void CSMTools::BodyPartCheckStage::perform (int stage, CSMDoc::Messages &message
{
const CSMWorld::Record<ESM::BodyPart> &record = mBodyParts.getRecord(stage);
if ( record.isDeleted() )
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::BodyPart &bodyPart = record.get();

View file

@ -17,6 +17,7 @@ namespace CSMTools
const CSMWorld::IdCollection<ESM::BodyPart> &mBodyParts;
const CSMWorld::Resources &mMeshes;
const CSMWorld::IdCollection<ESM::Race> &mRaces;
bool mIgnoreBaseRecords;
public:
BodyPartCheckStage(

View file

@ -6,14 +6,20 @@
#include <components/esm/loadclas.hpp>
#include <components/esm/loadskil.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
CSMTools::ClassCheckStage::ClassCheckStage (const CSMWorld::IdCollection<ESM::Class>& classes)
: mClasses (classes)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::ClassCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mClasses.getSize();
}
@ -21,7 +27,8 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Class>& record = mClasses.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::Class& class_ = record.get();

View file

@ -13,6 +13,7 @@ namespace CSMTools
class ClassCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Class>& mClasses;
bool mIgnoreBaseRecords;
public:

View file

@ -6,14 +6,20 @@
#include <components/esm/loadfact.hpp>
#include <components/esm/loadskil.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
CSMTools::FactionCheckStage::FactionCheckStage (const CSMWorld::IdCollection<ESM::Faction>& factions)
: mFactions (factions)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::FactionCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mFactions.getSize();
}
@ -21,7 +27,8 @@ void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages
{
const CSMWorld::Record<ESM::Faction>& record = mFactions.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::Faction& faction = record.get();

View file

@ -13,6 +13,7 @@ namespace CSMTools
class FactionCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
bool mIgnoreBaseRecords;
public:

View file

@ -2,14 +2,20 @@
#include <sstream>
#include "../prefs/state.hpp"
#include "../world/defaultgmsts.hpp"
CSMTools::GmstCheckStage::GmstCheckStage(const CSMWorld::IdCollection<ESM::GameSetting>& gameSettings)
: mGameSettings(gameSettings)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::GmstCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mGameSettings.getSize();
}
@ -17,7 +23,8 @@ void CSMTools::GmstCheckStage::perform(int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::GameSetting>& record = mGameSettings.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::GameSetting& gmst = record.get();

View file

@ -25,6 +25,7 @@ namespace CSMTools
private:
const CSMWorld::IdCollection<ESM::GameSetting>& mGameSettings;
bool mIgnoreBaseRecords;
std::string varTypeToString(ESM::VarType);

View file

@ -3,13 +3,19 @@
#include <set>
#include <sstream>
#include "../prefs/state.hpp"
CSMTools::JournalCheckStage::JournalCheckStage(const CSMWorld::IdCollection<ESM::Dialogue> &journals,
const CSMWorld::InfoCollection& journalInfos)
: mJournals(journals), mJournalInfos(journalInfos)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::JournalCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mJournals.getSize();
}
@ -17,7 +23,8 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Dialogue> &journalRecord = mJournals.getRecord(stage);
if (journalRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && journalRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || journalRecord.isDeleted())
return;
const ESM::Dialogue &journal = journalRecord.get();
@ -43,6 +50,10 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages)
statusNamedCount += 1;
}
// Skip "Base" records (setting!)
if (mIgnoreBaseRecords && infoRecord.mState == CSMWorld::RecordBase::State_BaseOnly)
continue;
if (journalInfo.mResponse.empty())
{
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId);

View file

@ -28,6 +28,7 @@ namespace CSMTools
const CSMWorld::IdCollection<ESM::Dialogue>& mJournals;
const CSMWorld::InfoCollection& mJournalInfos;
bool mIgnoreBaseRecords;
};
}

View file

@ -2,6 +2,8 @@
#include <components/misc/resourcehelpers.hpp>
#include "../prefs/state.hpp"
#include "../world/resources.hpp"
#include "../world/data.hpp"
@ -77,16 +79,26 @@ CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollect
mReferenceables(referenceables),
mIcons(icons),
mTextures(textures)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::MagicEffectCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mMagicEffects.getSize();
}
void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messages)
{
ESM::MagicEffect effect = mMagicEffects.getRecord(stage).get();
const CSMWorld::Record<ESM::MagicEffect> &record = mMagicEffects.getRecord(stage);
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
ESM::MagicEffect effect = record.get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, effect.mId);
if (effect.mData.mBaseCost < 0.0f)

View file

@ -24,6 +24,7 @@ namespace CSMTools
const CSMWorld::RefIdCollection &mReferenceables;
const CSMWorld::Resources &mIcons;
const CSMWorld::Resources &mTextures;
bool mIgnoreBaseRecords;
private:
bool isTextureExists(const std::string &texture, bool isIcon) const;

View file

@ -3,6 +3,8 @@
#include <sstream>
#include <algorithm>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
#include "../world/idcollection.hpp"
#include "../world/subcellcollection.hpp"
@ -10,10 +12,14 @@
CSMTools::PathgridCheckStage::PathgridCheckStage (const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& pathgrids)
: mPathgrids (pathgrids)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::PathgridCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mPathgrids.getSize();
}
@ -21,7 +27,8 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{
const CSMWorld::Record<CSMWorld::Pathgrid>& record = mPathgrids.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const CSMWorld::Pathgrid& pathgrid = record.get();

View file

@ -25,6 +25,7 @@ namespace CSMTools
{
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid,
CSMWorld::IdAccessor<CSMWorld::Pathgrid> >& mPathgrids;
bool mIgnoreBaseRecords;
public:

View file

@ -4,6 +4,8 @@
#include <components/esm/loadrace.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& messages)
@ -15,6 +17,14 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& me
const ESM::Race& race = record.get();
// Consider mPlayable flag even when "Base" records are ignored
if (race.mData.mFlags & 0x1)
mPlayable = true;
// Skip "Base" records (setting!)
if (mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly)
return;
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId);
// test for empty name and description
@ -38,10 +48,6 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& me
if (race.mData.mWeight.mFemale<0)
messages.push_back (std::make_pair (id, "female " + race.mId + " has negative weight"));
// remember playable flag
if (race.mData.mFlags & 0x1)
mPlayable = true;
/// \todo check data members that can't be edited in the table view
}
@ -55,11 +61,15 @@ void CSMTools::RaceCheckStage::performFinal (CSMDoc::Messages& messages)
CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races)
: mRaces (races), mPlayable (false)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::RaceCheckStage::setup()
{
mPlayable = false;
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mRaces.getSize()+1;
}

View file

@ -14,6 +14,7 @@ namespace CSMTools
{
const CSMWorld::IdCollection<ESM::Race>& mRaces;
bool mPlayable;
bool mIgnoreBaseRecords;
void performPerRecord (int stage, CSMDoc::Messages& messages);

View file

@ -2,6 +2,8 @@
#include <components/misc/stringops.hpp>
#include "../prefs/state.hpp"
#include "../world/record.hpp"
#include "../world/universalid.hpp"
@ -18,6 +20,7 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage(
mScripts(scripts),
mPlayerPresent(false)
{
mIgnoreBaseRecords = false;
}
void CSMTools::ReferenceableCheckStage::perform (int stage, CSMDoc::Messages& messages)
@ -228,6 +231,8 @@ void CSMTools::ReferenceableCheckStage::perform (int stage, CSMDoc::Messages& me
int CSMTools::ReferenceableCheckStage::setup()
{
mPlayerPresent = false;
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mReferencables.getSize() + 1;
}
@ -238,7 +243,8 @@ void CSMTools::ReferenceableCheckStage::bookCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Book& book = (dynamic_cast<const CSMWorld::Record<ESM::Book>& >(baseRecord)).get();
@ -257,7 +263,8 @@ void CSMTools::ReferenceableCheckStage::activatorCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Activator& activator = (dynamic_cast<const CSMWorld::Record<ESM::Activator>& >(baseRecord)).get();
@ -278,7 +285,8 @@ void CSMTools::ReferenceableCheckStage::potionCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Potion& potion = (dynamic_cast<const CSMWorld::Record<ESM::Potion>& >(baseRecord)).get();
@ -299,7 +307,8 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Apparatus& apparatus = (dynamic_cast<const CSMWorld::Record<ESM::Apparatus>& >(baseRecord)).get();
@ -320,7 +329,8 @@ void CSMTools::ReferenceableCheckStage::armorCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Armor& armor = (dynamic_cast<const CSMWorld::Record<ESM::Armor>& >(baseRecord)).get();
@ -347,7 +357,8 @@ void CSMTools::ReferenceableCheckStage::clothingCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Clothing& clothing = (dynamic_cast<const CSMWorld::Record<ESM::Clothing>& >(baseRecord)).get();
@ -365,7 +376,8 @@ void CSMTools::ReferenceableCheckStage::containerCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Container& container = (dynamic_cast<const CSMWorld::Record<ESM::Container>& >(baseRecord)).get();
@ -397,7 +409,8 @@ void CSMTools::ReferenceableCheckStage::creatureCheck (
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Creature& creature = (dynamic_cast<const CSMWorld::Record<ESM::Creature>&>(baseRecord)).get();
@ -473,7 +486,8 @@ void CSMTools::ReferenceableCheckStage::doorCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Door& door = (dynamic_cast<const CSMWorld::Record<ESM::Door>&>(baseRecord)).get();
@ -497,7 +511,8 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Ingredient& ingredient = (dynamic_cast<const CSMWorld::Record<ESM::Ingredient>& >(baseRecord)).get();
@ -516,10 +531,9 @@ void CSMTools::ReferenceableCheckStage::creaturesLevListCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
{
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
}
const ESM::CreatureLevList& CreatureLevList = (dynamic_cast<const CSMWorld::Record<ESM::CreatureLevList>& >(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_CreatureLevelledList, CreatureLevList.mId); //CreatureLevList but Type_CreatureLevelledList :/
@ -534,10 +548,9 @@ void CSMTools::ReferenceableCheckStage::itemLevelledListCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
{
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
}
const ESM::ItemLevList& ItemLevList = (dynamic_cast<const CSMWorld::Record<ESM::ItemLevList>& >(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_ItemLevelledList, ItemLevList.mId);
@ -551,7 +564,8 @@ void CSMTools::ReferenceableCheckStage::lightCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Light& light = (dynamic_cast<const CSMWorld::Record<ESM::Light>& >(baseRecord)).get();
@ -574,7 +588,8 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Lockpick& lockpick = (dynamic_cast<const CSMWorld::Record<ESM::Lockpick>& >(baseRecord)).get();
@ -595,7 +610,8 @@ void CSMTools::ReferenceableCheckStage::miscCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Miscellaneous& miscellaneous = (dynamic_cast<const CSMWorld::Record<ESM::Miscellaneous>& >(baseRecord)).get();
@ -619,6 +635,14 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
const ESM::NPC& npc = (dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(baseRecord)).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Npc, npc.mId);
//Detect if player is present
if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl?
mPlayerPresent = true;
// Skip "Base" records (setting!)
if (mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly)
return;
short level(npc.mNpdt.mLevel);
char disposition(npc.mNpdt.mDisposition);
char reputation(npc.mNpdt.mReputation);
@ -626,10 +650,6 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
//Don't know what unknown is for
int gold(npc.mNpdt.mGold);
//Detect if player is present
if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl?
mPlayerPresent = true;
if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated
{
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
@ -728,7 +748,8 @@ void CSMTools::ReferenceableCheckStage::weaponCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Weapon& weapon = (dynamic_cast<const CSMWorld::Record<ESM::Weapon>& >(baseRecord)).get();
@ -808,7 +829,8 @@ void CSMTools::ReferenceableCheckStage::probeCheck(
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Probe& probe = (dynamic_cast<const CSMWorld::Record<ESM::Probe>& >(baseRecord)).get();
@ -827,7 +849,8 @@ void CSMTools::ReferenceableCheckStage::repairCheck (
{
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Repair& repair = (dynamic_cast<const CSMWorld::Record<ESM::Repair>& >(baseRecord)).get();
@ -846,7 +869,8 @@ void CSMTools::ReferenceableCheckStage::staticCheck (
{
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
if (baseRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && baseRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || baseRecord.isDeleted())
return;
const ESM::Static& staticElement = (dynamic_cast<const CSMWorld::Record<ESM::Static>& >(baseRecord)).get();

View file

@ -82,6 +82,7 @@ namespace CSMTools
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
const CSMWorld::IdCollection<ESM::Script>& mScripts;
bool mPlayerPresent;
bool mIgnoreBaseRecords;
};
}
#endif // REFERENCEABLECHECKSTAGE_H

View file

@ -1,5 +1,7 @@
#include "referencecheck.hpp"
#include "../prefs/state.hpp"
CSMTools::ReferenceCheckStage::ReferenceCheckStage(
const CSMWorld::RefCollection& references,
const CSMWorld::RefIdCollection& referencables,
@ -12,13 +14,15 @@ CSMTools::ReferenceCheckStage::ReferenceCheckStage(
mCells(cells),
mFactions(factions)
{
mIgnoreBaseRecords = false;
}
void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &messages)
{
const CSMWorld::Record<CSMWorld::CellRef>& record = mReferences.getRecord(stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const CSMWorld::CellRef& cellRef = record.get();
@ -100,5 +104,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message
int CSMTools::ReferenceCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mReferences.getSize();
}

View file

@ -23,6 +23,7 @@ namespace CSMTools
const CSMWorld::RefIdData& mDataSet;
const CSMWorld::IdCollection<CSMWorld::Cell>& mCells;
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
bool mIgnoreBaseRecords;
};
}

View file

@ -5,14 +5,20 @@
#include <components/esm/loadregn.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
CSMTools::RegionCheckStage::RegionCheckStage (const CSMWorld::IdCollection<ESM::Region>& regions)
: mRegions (regions)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::RegionCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mRegions.getSize();
}
@ -20,7 +26,8 @@ void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Region>& record = mRegions.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::Region& region = record.get();

View file

@ -13,6 +13,7 @@ namespace CSMTools
class RegionCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Region>& mRegions;
bool mIgnoreBaseRecords;
public:

View file

@ -60,6 +60,8 @@ CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document)
Compiler::registerExtensions (mExtensions);
mContext.setExtensions (&mExtensions);
mIgnoreBaseRecords = false;
}
int CSMTools::ScriptCheckStage::setup()
@ -78,17 +80,25 @@ int CSMTools::ScriptCheckStage::setup()
mId.clear();
Compiler::ErrorHandler::reset();
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mDocument.getData().getScripts().getSize();
}
void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Script> &record = mDocument.getData().getScripts().getRecord(stage);
mId = mDocument.getData().getScripts().getId (stage);
if (mDocument.isBlacklisted (
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Script, mId)))
return;
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
mMessages = &messages;
switch (mWarningMode)
@ -100,10 +110,8 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
try
{
const CSMWorld::Data& data = mDocument.getData();
mFile = data.getScripts().getRecord (stage).get().mId;
std::istringstream input (data.getScripts().getRecord (stage).get().mScriptText);
mFile = record.get().mId;
std::istringstream input (record.get().mScriptText);
Compiler::Scanner scanner (*this, input, mContext.getExtensions());

View file

@ -32,6 +32,7 @@ namespace CSMTools
std::string mFile;
CSMDoc::Messages *mMessages;
WarningMode mWarningMode;
bool mIgnoreBaseRecords;
CSMDoc::Message::Severity getSeverity (Type type);

View file

@ -22,7 +22,8 @@ void CSMTools::Search::searchTextCell (const CSMWorld::IdTableBase *model,
int pos = 0;
while ((pos = text.indexOf (search, pos, Qt::CaseInsensitive))!=-1)
Qt::CaseSensitivity caseSensitivity = mCase ? Qt::CaseSensitive : Qt::CaseInsensitive;
while ((pos = text.indexOf (search, pos, caseSensitivity))!=-1)
{
std::ostringstream hint;
hint
@ -120,25 +121,26 @@ QString CSMTools::Search::flatten (const QString& text) const
return flat;
}
CSMTools::Search::Search() : mType (Type_None), mValue (0), mIdColumn (0), mTypeColumn (0),
CSMTools::Search::Search() : mType (Type_None), mValue (0), mCase (false), mIdColumn (0), mTypeColumn (0),
mPaddingBefore (10), mPaddingAfter (10) {}
CSMTools::Search::Search (Type type, const std::string& value)
: mType (type), mText (value), mValue (0), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
CSMTools::Search::Search (Type type, bool caseSensitive, const std::string& value)
: mType (type), mText (value), mValue (0), mCase (caseSensitive), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
{
if (type!=Type_Text && type!=Type_Id)
throw std::logic_error ("Invalid search parameter (string)");
}
CSMTools::Search::Search (Type type, const QRegExp& value)
: mType (type), mRegExp (value), mValue (0), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
CSMTools::Search::Search (Type type, bool caseSensitive, const QRegExp& value)
: mType (type), mRegExp (value), mValue (0), mCase (caseSensitive), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
{
mRegExp.setCaseSensitivity(mCase ? Qt::CaseSensitive : Qt::CaseInsensitive);
if (type!=Type_TextRegEx && type!=Type_IdRegEx)
throw std::logic_error ("Invalid search parameter (RegExp)");
}
CSMTools::Search::Search (Type type, int value)
: mType (type), mValue (value), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
CSMTools::Search::Search (Type type, bool caseSensitive, int value)
: mType (type), mValue (value), mCase (caseSensitive), mIdColumn (0), mTypeColumn (0), mPaddingBefore (10), mPaddingAfter (10)
{
if (type!=Type_RecordState)
throw std::logic_error ("invalid search parameter (int)");

View file

@ -43,6 +43,7 @@ namespace CSMTools
std::string mText;
QRegExp mRegExp;
int mValue;
bool mCase;
std::set<int> mColumns;
int mIdColumn;
int mTypeColumn;
@ -67,11 +68,11 @@ namespace CSMTools
Search();
Search (Type type, const std::string& value);
Search (Type type, bool caseSensitive, const std::string& value);
Search (Type type, const QRegExp& value);
Search (Type type, bool caseSensitive, const QRegExp& value);
Search (Type type, int value);
Search (Type type, bool caseSensitive, int value);
// Configure search for the specified model.
void configure (const CSMWorld::IdTableBase *model);

View file

@ -4,14 +4,20 @@
#include <components/esm/loadskil.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
CSMTools::SkillCheckStage::SkillCheckStage (const CSMWorld::IdCollection<ESM::Skill>& skills)
: mSkills (skills)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::SkillCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mSkills.getSize();
}
@ -19,7 +25,8 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Skill>& record = mSkills.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::Skill& skill = record.get();

View file

@ -13,6 +13,7 @@ namespace CSMTools
class SkillCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Skill>& mSkills;
bool mIgnoreBaseRecords;
public:

View file

@ -4,14 +4,20 @@
#include <components/esm/loadskil.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection<ESM::Sound>& sounds)
: mSounds (sounds)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::SoundCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mSounds.getSize();
}
@ -19,7 +25,8 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Sound>& record = mSounds.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::Sound& sound = record.get();

View file

@ -13,6 +13,7 @@ namespace CSMTools
class SoundCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Sound>& mSounds;
bool mIgnoreBaseRecords;
public:

View file

@ -2,6 +2,8 @@
#include <sstream>
#include "../prefs/state.hpp"
#include "../world/refiddata.hpp"
#include "../world/universalid.hpp"
@ -11,20 +13,24 @@ CSMTools::SoundGenCheckStage::SoundGenCheckStage(const CSMWorld::IdCollection<ES
: mSoundGens(soundGens),
mSounds(sounds),
mReferenceables(referenceables)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::SoundGenCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mSoundGens.getSize();
}
void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages)
{
const CSMWorld::Record<ESM::SoundGenerator> &record = mSoundGens.getRecord(stage);
if (record.isDeleted())
{
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
}
const ESM::SoundGenerator& soundGen = record.get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_SoundGen, soundGen.mId);

View file

@ -13,6 +13,7 @@ namespace CSMTools
const CSMWorld::IdCollection<ESM::SoundGenerator> &mSoundGens;
const CSMWorld::IdCollection<ESM::Sound> &mSounds;
const CSMWorld::RefIdCollection &mReferenceables;
bool mIgnoreBaseRecords;
public:
SoundGenCheckStage(const CSMWorld::IdCollection<ESM::SoundGenerator> &soundGens,

View file

@ -5,14 +5,20 @@
#include <components/esm/loadspel.hpp>
#include "../prefs/state.hpp"
#include "../world/universalid.hpp"
CSMTools::SpellCheckStage::SpellCheckStage (const CSMWorld::IdCollection<ESM::Spell>& spells)
: mSpells (spells)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::SpellCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mSpells.getSize();
}
@ -20,7 +26,8 @@ void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Spell>& record = mSpells.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
const ESM::Spell& spell = record.get();

View file

@ -13,6 +13,7 @@ namespace CSMTools
class SpellCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Spell>& mSpells;
bool mIgnoreBaseRecords;
public:

View file

@ -1,18 +1,23 @@
#include "startscriptcheck.hpp"
#include "../prefs/state.hpp"
#include <components/misc/stringops.hpp>
CSMTools::StartScriptCheckStage::StartScriptCheckStage (
const CSMWorld::IdCollection<ESM::StartScript>& startScripts,
const CSMWorld::IdCollection<ESM::Script>& scripts)
: mStartScripts (startScripts), mScripts (scripts)
{}
{
mIgnoreBaseRecords = false;
}
void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::StartScript>& record = mStartScripts.getRecord (stage);
if (record.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
std::string scriptId = record.get().mId;
@ -26,5 +31,7 @@ void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messa
int CSMTools::StartScriptCheckStage::setup()
{
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mStartScripts.getSize();
}

View file

@ -14,6 +14,7 @@ namespace CSMTools
{
const CSMWorld::IdCollection<ESM::StartScript>& mStartScripts;
const CSMWorld::IdCollection<ESM::Script>& mScripts;
bool mIgnoreBaseRecords;
public:

View file

@ -2,6 +2,8 @@
#include <sstream>
#include "../prefs/state.hpp"
#include "../world/infoselectwrapper.hpp"
CSMTools::TopicInfoCheckStage::TopicInfoCheckStage(
@ -29,7 +31,9 @@ CSMTools::TopicInfoCheckStage::TopicInfoCheckStage(
mTopics(topics),
mReferencables(referencables),
mSoundFiles(soundFiles)
{}
{
mIgnoreBaseRecords = false;
}
int CSMTools::TopicInfoCheckStage::setup()
{
@ -67,6 +71,8 @@ int CSMTools::TopicInfoCheckStage::setup()
}
}
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mTopicInfos.getSize();
}
@ -74,7 +80,8 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message
{
const CSMWorld::Record<CSMWorld::Info>& infoRecord = mTopicInfos.getRecord(stage);
if (infoRecord.isDeleted())
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && infoRecord.mState == CSMWorld::RecordBase::State_BaseOnly) || infoRecord.isDeleted())
return;
const CSMWorld::Info& topicInfo = infoRecord.get();

View file

@ -65,6 +65,8 @@ namespace CSMTools
std::set<std::string> mCellNames;
bool mIgnoreBaseRecords;
// These return false when not successful and write an error
bool verifyActor(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
bool verifyCell(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);

View file

@ -88,6 +88,7 @@ namespace CSMWorld
Display_UnsignedInteger8,
Display_Integer,
Display_Float,
Display_Double,
Display_Var,
Display_GmstVarType,
Display_GlobalVarType,

View file

@ -136,7 +136,7 @@ namespace CSMWorld
struct VarTypeColumn : public Column<ESXRecordT>
{
VarTypeColumn (ColumnBase::Display display)
: Column<ESXRecordT> (Columns::ColumnId_ValueType, display)
: Column<ESXRecordT> (Columns::ColumnId_ValueType, display, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
@ -161,7 +161,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct VarValueColumn : public Column<ESXRecordT>
{
VarValueColumn() : Column<ESXRecordT> (Columns::ColumnId_Value, ColumnBase::Display_Var) {}
VarValueColumn() : Column<ESXRecordT> (Columns::ColumnId_Value, ColumnBase::Display_Var, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -1371,7 +1371,7 @@ namespace CSMWorld
RotColumn (ESM::Position ESXRecordT::* position, int index, bool door)
: Column<ESXRecordT> (
(door ? Columns::ColumnId_DoorPositionXRot : Columns::ColumnId_PositionXRot)+index,
ColumnBase::Display_Float), mPosition (position), mIndex (index) {}
ColumnBase::Display_Double), mPosition (position), mIndex (index) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{

View file

@ -84,15 +84,28 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value
if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole)
{
mIdCollection->setData (index.row(), index.column(), value);
emit dataChanged(index, index);
// Modifying a value can also change the Modified status of a record.
int stateColumn = searchColumnIndex(Columns::ColumnId_Modification);
if (stateColumn != -1)
{
QModelIndex stateIndex = this->index(index.row(), stateColumn);
emit dataChanged(stateIndex, stateIndex);
}
if (index.column() == stateColumn)
{
// modifying the state column can modify other values. we need to tell
// views that the whole row has changed.
emit dataChanged(this->index(index.row(), 0),
this->index(index.row(), columnCount(index.parent())));
} else
{
emit dataChanged(index, index);
// Modifying a value can also change the Modified status of a record.
QModelIndex stateIndex = this->index(index.row(), stateColumn);
emit dataChanged(stateIndex, stateIndex);
}
} else
emit dataChanged(index, index);
return true;
}

View file

@ -184,11 +184,11 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float));
new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Double));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float));
new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Double));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float));
new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Double));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_AiPackageList,

View file

@ -101,15 +101,39 @@ void CSVDoc::View::setupFileMenu()
file->addAction(exit);
}
namespace
{
void updateUndoRedoAction(QAction *action, const std::string &settingsKey)
{
QKeySequence seq;
CSMPrefs::State::get().getShortcutManager().getSequence(settingsKey, seq);
action->setShortcut(seq);
}
}
void CSVDoc::View::undoActionChanged()
{
updateUndoRedoAction(mUndo, "document-edit-undo");
}
void CSVDoc::View::redoActionChanged()
{
updateUndoRedoAction(mRedo, "document-edit-redo");
}
void CSVDoc::View::setupEditMenu()
{
QMenu *edit = menuBar()->addMenu (tr ("Edit"));
mUndo = mDocument->getUndoStack().createUndoAction (this, tr("Undo"));
setupShortcut("document-edit-undo", mUndo);
connect(mUndo, SIGNAL (changed ()), this, SLOT (undoActionChanged ()));
edit->addAction (mUndo);
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("Redo"));
mRedo = mDocument->getUndoStack().createRedoAction (this, tr("Redo"));
connect(mRedo, SIGNAL (changed ()), this, SLOT (redoActionChanged ()));
setupShortcut("document-edit-redo", mRedo);
edit->addAction (mRedo);
@ -622,6 +646,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
}
assert(view);
view->setParent(this);
view->setEditLock (mDocument->getState() & CSMDoc::State_Locked);
mSubViews.append(view); // only after assert
int minWidth = windows["minimum-width"].toInt();

View file

@ -152,6 +152,10 @@ namespace CSVDoc
void settingChanged (const CSMPrefs::Setting *setting);
void undoActionChanged();
void redoActionChanged();
void newView();
void save();

Some files were not shown because too many files have changed in this diff Show more