From 208cd993d471c1a1f5d1267e7b9b28c282d4ee66 Mon Sep 17 00:00:00 2001 From: Gleb Date: Sun, 1 Sep 2024 22:44:58 +0100 Subject: [PATCH] Inventory prototype --- .../Common/Data/Input/MoveAndOrbit.inputmap | 40 +- Content/Common/Data/Items/FirstAidKit.json | 5 + Content/Common/Data/Items/RedKey.json | 5 + Content/Common/Data/Objects/RedKey.prefab | 390 ++++++++++++++++++ .../SurvivalPack/Meshes/FirstAidKit.mdl | Bin 0 -> 50756 bytes .../SurvivalPack/Prefabs/FirstAidKit.prefab | 132 ++++++ Content/Common/Data/Scenes/Inventory.scene | 160 +++++++ Content/Common/Data/Scenes/Sample.xml | 36 +- Content/Common/Data/UI/Inventory.rml | 35 ++ Directory.Build.props | 2 +- RbfxTemplate/DoorButton.cs | 2 +- RbfxTemplate/DoorTrigger.cs | 8 +- RbfxTemplate/GameRmlUIComponent.cs | 8 +- RbfxTemplate/GameSettings.cs | 3 + RbfxTemplate/GameState.cs | 49 ++- RbfxTemplate/Inventory/ExtensionMethods.cs | 10 + RbfxTemplate/{ => Inventory}/InventoryItem.cs | 6 +- RbfxTemplate/Inventory/InventorySlot.cs | 9 + RbfxTemplate/Inventory/ItemDefinition.cs | 35 ++ .../Inventory/ItemDefinitionResource.cs | 17 + RbfxTemplate/InventoryState.cs | 110 +++++ RbfxTemplate/Player.cs | 41 +- RbfxTemplate/Selectable.cs | 2 +- RbfxTemplate/StateStack.cs | 7 +- RbfxTemplate/UrhoPluginApplication.cs | 18 +- 25 files changed, 1067 insertions(+), 63 deletions(-) create mode 100644 Content/Common/Data/Items/FirstAidKit.json create mode 100644 Content/Common/Data/Items/RedKey.json create mode 100644 Content/Common/Data/Objects/RedKey.prefab create mode 100644 Content/Common/Data/Quaternius/SurvivalPack/Meshes/FirstAidKit.mdl create mode 100644 Content/Common/Data/Quaternius/SurvivalPack/Prefabs/FirstAidKit.prefab create mode 100644 Content/Common/Data/Scenes/Inventory.scene create mode 100644 Content/Common/Data/UI/Inventory.rml create mode 100644 RbfxTemplate/Inventory/ExtensionMethods.cs rename RbfxTemplate/{ => Inventory}/InventoryItem.cs (75%) create mode 100644 RbfxTemplate/Inventory/InventorySlot.cs create mode 100644 RbfxTemplate/Inventory/ItemDefinition.cs create mode 100644 RbfxTemplate/Inventory/ItemDefinitionResource.cs create mode 100644 RbfxTemplate/InventoryState.cs diff --git a/Content/Common/Data/Input/MoveAndOrbit.inputmap b/Content/Common/Data/Input/MoveAndOrbit.inputmap index fdcb1ed..94b47fb 100644 --- a/Content/Common/Data/Input/MoveAndOrbit.inputmap +++ b/Content/Common/Data/Input/MoveAndOrbit.inputmap @@ -122,23 +122,39 @@ ] } }, - { - "key": "Use", - "value": { - "buttons": [ + { + "key": "Use", + "value": { + "buttons": [ { - "button": "X", - "controller": true + "button": "X", + "controller": true } - ], - "keys": [ - { - "scancode": "E" + ], + "keys": [ + { + "scancode": "E" + } + ], + "mouseButtons": [ + { + "button": "Left" + } + ] + } + }, + { + "key": "Inventory", + "value": { + "buttons": [ + { + "button": "Y", + "controller": true } ], - "mouseButtons": [ + "keys": [ { - "button": "Left" + "scancode": "I" } ] } diff --git a/Content/Common/Data/Items/FirstAidKit.json b/Content/Common/Data/Items/FirstAidKit.json new file mode 100644 index 0000000..900c992 --- /dev/null +++ b/Content/Common/Data/Items/FirstAidKit.json @@ -0,0 +1,5 @@ +{ + "name": "First Aid Kit", + "prefab": "PrefabResource;Quaternius/SurvivalPack/Prefabs/FirstAidKit.prefab", + "weight": 1.0 +} \ No newline at end of file diff --git a/Content/Common/Data/Items/RedKey.json b/Content/Common/Data/Items/RedKey.json new file mode 100644 index 0000000..23bbd52 --- /dev/null +++ b/Content/Common/Data/Items/RedKey.json @@ -0,0 +1,5 @@ +{ + "name": "Red Key", + "prefab": "PrefabResource;Objects/RedKey.prefab", + "weight": 0.1 +} \ No newline at end of file diff --git a/Content/Common/Data/Objects/RedKey.prefab b/Content/Common/Data/Objects/RedKey.prefab new file mode 100644 index 0000000..04abc93 --- /dev/null +++ b/Content/Common/Data/Objects/RedKey.prefab @@ -0,0 +1,390 @@ +{ + "components": [ + { + "_typeName": "Octree" + }, + { + "_typeName": "PhysicsWorld" + }, + { + "_typeName": "RenderPipeline", + "attributes": [ + { + "name": "Render Passes", + "type": "VariantVector", + "value": [ + { + "type": "String", + "value": "Postprocess: Exposure" + }, + { + "type": "Bool", + "value": true + }, + { + "type": "String", + "value": "Postprocess: SSAO" + }, + { + "type": "Bool", + "value": false + }, + { + "type": "String", + "value": "Postprocess: Bloom" + }, + { + "type": "Bool", + "value": false + }, + { + "type": "String", + "value": "Postprocess: Draw Outlines" + }, + { + "type": "Bool", + "value": true + }, + { + "type": "String", + "value": "Postprocess: Tone Mapping" + }, + { + "type": "Bool", + "value": true + }, + { + "type": "String", + "value": "Postprocess: Adjust Color" + }, + { + "type": "Bool", + "value": true + }, + { + "type": "String", + "value": "Postprocess: FXAA v2" + }, + { + "type": "Bool", + "value": false + }, + { + "type": "String", + "value": "Postprocess: FXAA v3" + }, + { + "type": "Bool", + "value": false + } + ] + }, + { + "name": "Render Path Parameters", + "type": "StringVariantMap", + "value": [ + { + "key": "SSAO: Near Distance", + "type": "Float", + "value": 1.0 + }, + { + "key": "Exposure: Adapt Rate", + "type": "Float", + "value": 0.6000000238418579 + }, + { + "key": "Exposure: Min", + "type": "Float", + "value": 1.0 + }, + { + "key": "Bloom: Max Brightness", + "type": "Float", + "value": 1.0 + }, + { + "key": "SSAO: Normal Threshold", + "type": "Float", + "value": 0.20000000298023225 + }, + { + "key": "SSAO: Near Radius", + "type": "Float", + "value": 0.05000000074505806 + }, + { + "key": "SSAO: Strength", + "type": "Float", + "value": 0.699999988079071 + }, + { + "key": "Adjust Color: HSVParams", + "type": "Vector4", + "value": "1 1 1 1" + }, + { + "key": "SSAO: End Fade Distance", + "type": "Float", + "value": 200.0 + }, + { + "key": "Exposure: Automatic", + "type": "Bool", + "value": false + }, + { + "key": "Tone Mapping: Mode@", + "type": "StringVector", + "value": [ + "None", + "Reinhard", + "ReinhardWhite", + "Uncharted2" + ] + }, + { + "key": "SSAO: Begin Fade Distance", + "type": "Float", + "value": 100.0 + }, + { + "key": "Adjust Color: ColorOffset", + "type": "Vector4", + "value": "0 0 0 0" + }, + { + "key": "Bloom: Base Intensity", + "type": "Float", + "value": 1.0 + }, + { + "key": "Bloom: Iteration Intensity Factor", + "type": "Float", + "value": 1.0 + }, + { + "key": "Bloom: Min Brightness", + "type": "Float", + "value": 0.800000011920929 + }, + { + "key": "SSAO: Depth Threshold", + "type": "Float", + "value": 0.10000000149011612 + }, + { + "key": "SSAO: Far Distance", + "type": "Float", + "value": 100.0 + }, + { + "key": "SSAO: Downscale", + "type": "Int", + "value": 0 + }, + { + "key": "Exposure: Max", + "type": "Float", + "value": 3.0 + }, + { + "key": "Adjust Color: ColorFilter", + "type": "Vector4", + "value": "1 1 1 1" + }, + { + "key": "SSAO: Exponent", + "type": "Float", + "value": 1.5 + }, + { + "key": "FXAA: FXAAParams", + "type": "Vector3", + "value": "0.4 0.5 0.75" + }, + { + "key": "SSAO: Far Radius", + "type": "Float", + "value": 1.0 + }, + { + "key": "Bloom: Num Iterations", + "type": "Int", + "value": 5 + }, + { + "key": "Tone Mapping: Mode", + "type": "Int", + "value": 0 + } + ] + } + ] + }, + { + "_typeName": "ReflectionProbeManager" + } + ], + "nodes": [ + { + "attributes": [ + { + "name": "Name", + "type": "String", + "value": "RedKey" + }, + { + "name": "Tags", + "type": "StringVector", + "value": [ + "Selectable", + "DoorKey" + ] + } + ], + "components": [ + { + "_typeName": "CollisionShape", + "attributes": [ + { + "name": "Size", + "type": "Vector3", + "value": "0.3 0.05 0.2" + } + ] + }, + { + "_typeName": "RigidBody", + "attributes": [ + { + "name": "Mass", + "type": "Float", + "value": 0.10000000149011612 + } + ] + }, + { + "_typeName": "InventoryItem", + "attributes": [ + { + "name": "Item Definition", + "type": "ResourceRef", + "value": "ItemDefinitionResource;Items/RedKey.json" + }, + { + "name": "Tooltip", + "type": "String", + "value": "Red Key" + } + ] + } + ], + "nodes": [ + { + "attributes": [ + { + "name": "Name", + "type": "String", + "value": "Visual" + }, + { + "name": "Scale", + "type": "Vector3", + "value": "0.3 0.05 0.2" + } + ], + "components": [ + { + "_typeName": "StaticModel", + "attributes": [ + { + "name": "Model", + "type": "ResourceRef", + "value": "Model;Models/Box.mdl" + }, + { + "name": "Material", + "type": "ResourceRefList", + "value": "Material;Materials/RedKey.material" + }, + { + "name": "Cast Shadows", + "type": "Bool", + "value": true + } + ] + } + ] + } + ] + }, + { + "attributes": [ + { + "name": "Name", + "type": "String", + "value": "Default Skybox" + } + ], + "components": [ + { + "_typeName": "Skybox", + "attributes": [ + { + "name": "Model", + "type": "ResourceRef", + "value": "Model;Models/Box.mdl" + }, + { + "name": "Material", + "type": "ResourceRefList", + "value": "Material;Materials/DefaultSkybox.xml" + } + ] + } + ] + }, + { + "attributes": [ + { + "name": "Name", + "type": "String", + "value": "Default Zone" + } + ], + "components": [ + { + "_typeName": "Zone", + "attributes": [ + { + "name": "Bounding Box Min", + "type": "Vector3", + "value": "-1000 -1000 -1000" + }, + { + "name": "Bounding Box Max", + "type": "Vector3", + "value": "1000 1000 1000" + }, + { + "name": "Ambient Color", + "type": "Color", + "value": "0 0 0 1" + }, + { + "name": "Background Brightness", + "type": "Float", + "value": 1.0 + }, + { + "name": "Zone Texture", + "type": "ResourceRef", + "value": "TextureCube;Textures/DefaultSkybox.xml" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Content/Common/Data/Quaternius/SurvivalPack/Meshes/FirstAidKit.mdl b/Content/Common/Data/Quaternius/SurvivalPack/Meshes/FirstAidKit.mdl new file mode 100644 index 0000000000000000000000000000000000000000..7a4993251cd935f410c2571ed62059ac419d00d6 GIT binary patch literal 50756 zcmb822bdH^)5p7ejwqraU_eEJAS&?)3b(UjCMhC81QAda%;ca%1<6PdQBXhxL;>Xv z5aD)Kf=WgK2_ll?s~|y8(tZD$?Rnq!?77;{b*p=h-_uV`hwAQ{+McEj@2@I_5Z9#$ zf&Ya=U;H6=E?m=v{;yx_Rc@Vgo!xTPHm0qt-6uL>-?G@Ex(6e7=FOWW#HxEW)?bMJ z(W&1rbJzFj?pC_{YL{cj7SD7)=yfJ?>h%IFJ9^-9_to=%L?%}Jj@4n&1Mj={6&~kq zyCv0qeZ*>aOsVsc5pKt*P2Yi!OmsIw-?yvOX4yj<)BSsUrgLeQ{ie!%_tb$A?zd-d zVOg_&cTVpXEf*W&cG$bfTE9DLE^}k&-f^!xxG9ZeM|{52twZ(jO(B)t zVx;di(6<@%Z5E<0l}jv@%dvlgozUw{>{_t-Q10lNbr&=bDVKC0_8sWJvFC4JA*L=^-bqk`$M;S%RKZ4FM|HSv2Wjy=|u~V^LC;?aBTMz%e=LHx_hY@ z#~f?wFd?I(_h7kR@#d?yX4=Nv-b<6c)oUkuS^1BqacqyRA9}5wN#3gCH@F;Y-W$i7 zV<_LemhNL`dPUD4`N67hu`fPwp|86G`f{u&Gs$h^OmbI3Uye1$CdUpqnBOBC)$-5U zZkKa|m;MyL!!7vq8&-RE{M;ljuzehRG3x`rT(W%}TV>f5ez}#_rLyd*7iz`ULEj2r zr@1sYjM-Gt-5#;)J91F%*gddOZ}+IivOhN|9SO>v@y_41dwLbzZ4cSY{rKfFk)T|T zU0Nx(KVQ(j#WoMFeG>J1Wk~(5Ym&>KFQ_dz)|`hp)|`hp_ASg=m}9-+dd`|x>U?Zi z$oxh+U=Hwh>bWo{mgcNK4vg?t>p3eYmgYjT56|nlFei4w_W52g7uL+T!>d#1bY%H2 z?XCUysc42r>xXtImt)QT%dzIT;MjJ3CU`Wr6oXwqw`Q;R_ws|Oe=oP|ODxS(Z@97{S7djsl$W3^57=YT5` z_BTE_#Qthq?WJLU<5;q(!TiRtWUGU@g=48tQeS@#eX;`j?{$Sv$5w{)U+U|@7~)v! zlfl^J*bA`L!Ic1G{Xa$;%E5Udetua^_6_c-1IdJmZ+i}eom^`|k%w!?a7 zY5Wc^Y`tUF8ONIAjbkfgy+dO&6>9>HrS;Al=vzgvcRFpV=>43-ddEe%!}WS6Cw3>+ zJIR(y>z!oF&BS^qxVJS}?;J$^=Cs}k+Ja-vwFbwUYZ#6-_k}IW{^(8_FerAo5WnB# zSaUzmvF7@WW6gcx6y30rYEU`hxHkiTORs0gTBo|^rdqD zoOw&+LzK(0bZ>z_Dj9tPe-y`>_P1^4zR_)U+E(3GXRoz>$^KHEQT;vxb_m!ZIk17P z=E@}bf9vB`c01%=ho&YzXX_j46F zcQlPF*YtC7Y{zYRe4p5yM#Wu@T{p691bZ@fe0p);7c>X=cK_U~toIh*P%iR4{Bn=( zKbA&5rkvPSxywe5qJEE}eu>Rjzh5-Zwf6dLIWrPVR)=jzYsHe);ikW9#gf&b`I#%c zpg-(6zM-+7GVr(YGn*NfNQyMQu8^@1@wDE$(IQD9xKX9z+ z1L0U2$K)^h5`BkbX&ko#JMn+xIG&R8IQF{zZyblRYZK$x!#GZ*ah$(?zxd%|_Hm)d zTT-kZ$4Tk%BQuE8sfSG0KhN!Izzv^yMY z+B1$dZ8gW5HtOr@54uZQ^p3B}JI$)ES-%_`)GzsTIo7m&9IJKkZS|MXcX5l}(d+Zs z^)=T<9BZz*I9A`A|9qZfbsPJAa&e+R#LI;A2Xnk}tT~Q3R`(tM`7y`p`51HZ$*Rv{ zKAzU?J@37c`PjTSjx}}QSaUzbvD)sy_MA-DX&2B;NIq3+!9Ns-RRzkokew4ygron!3}+Hd5+f97#4#XQk-9K`pr zY%s^-IWMb&$xco@KaTHQz12EznmTZ-_9=LXkMcM+Si>OhDwAW)zFttrb9FxQgH>O1 z3~{X9AG?S@^EftGBOF_wtuvi382h8@@)j@8dMeLKmq6wgJ^ z^6`9=)j>bsbn$%CqkZ>4#B<^Krd3~x=fZPH7tc3Ymg2eaeA6#?3gWq*O~i9q%hk^} z{c<^$;<?@wh{4MLtVSw z(a$VB#2~Y*jzRVigUqsYZ-^W85HroPI>yDHV{0HDCW?5j6~DB%*00$oIo9m!9IN9h zT*Tyf9INA_D4xqZjd-r}%MWIpUvAe|$9DL07RTxsj0oa?lPVW+SN=K3zK1kIg4ZI-e@jFEVjq7!5*D#bs^Z_N6++%p9-R^83 zSUm@Lhu6kigIO^&6$9*iN5)iII&*yPy2XG3$#EFI6) zA!I(*{yu-s;#hkAhIl!DJ;||pP2eKVoYlb`Llm1dDiP0RtzUB-bF66}IMy7S9INBc z{Iwj#ezi%&b6NE@#|6ileTQSsKFP6qPZq;(Vf;NAevcDL581z&{z?6NoKTkbBA5&P zwI|2w-|kRshrfTzQHMnQx`&u)kK)W%CgQoQ^=pnHjy3C-V=11C#wKFCSsirzx`+7n zU=2g@TvmN`{JMwub(W=gF2t`VRj!U-PpVvs=L+s^Db_n@67gJCeRcf0-xeHet_e8S zT*Gjzxrc0p_^8E+crL5H<~oXF&HX&bntM}@HTQ*&LEoi`crL5H=Dv_)&9xlIn)S=E zL43)3un!cQG-FGX^ch>WSofP0(|}kXe;g;n()!^f#yrRBxT_fAu9DILF;5iF4@jD)~{(NlVPbX z5O;<3y&wCPj@U12xugT)uKfDtSRGSF@mxuj8`N(y<&rOm{C(WLnSMl$HRmkyUE%kT z9)1sLtp{`6$Fb&ml4H%ekYmm9MzK_nAfD@sf;+7G>KGz_3~{XK3*uPQ$CM=N;`fD_ z6ic-f@m%Xd{88q*k7LdCB*)UdA$HvN|8i^)&qeyuy*-Y2uDK!gYnIEgrhVX8-NwFs z;8-)B>$XH3NOaeQi4mK>+I$Ylv8In{c_I!ZdZgsl)^dY*F2sRka;)j+;#eIA;vx>j z<5(RB;vx>jUmH=37UDpx`Ude_hy%$aA5%_j_INJDfkclKv)3=hb0JrlVi=82JYU>crN|y z*2VKbOh~v49@O>bOh~ahbt5j^CH_IQ9^i8I0plHhVl5;xgli%e2~u?D1SVu|Ygn zGCEK^7sXN~b8lummyXMf-x@NGgLp1#Hyslh-tHODc>n)ZQX&GDA5~$C~%Xv1XldEXBAW9){v~ydM+sI~j=IvHBl${0_zBcq0<=I~j=I31tzt zLa{zP3mp&-L-9MFj^D{Z{EoF;ibWw7F*zQ^&Rl-%B;s}ZTUoj{#H~aSx8mve9mMe1 zSsmjNAsv!ogF54M&@nlFosC5NPPx(FRzv)bRbL(Jw|Vns*~q4}+6n zi)$9;#<+5+9)f$@Q*UqVmmT?{Z~ofUTEAwUaqPl*w|V1#TI_yaczKLtpDJ0|Yh5<( zo{xROvd@4W-tjYc_l0edws>~j8_$r#&bzu6_cn0LY`68oy-BguAG%!gEz2&(y^Y1a zO)tEhWvdUV>e9WP#=WJa_l$n^YiD=l*WXvO^@l28TY>#6_CwoGN>{20W z>kno>!q7{yfvG!lHuXC)~Cpp%%XB=zV$?oV6zoLF? zcBx>szirUQBT>HxE^Lc&>;|+k*@tH^<~i2Xmt#$R`@{bBO4whkzUF+vu|;5a-h!=u zX5ro#$C~xPv1E6GH38X&5{PwtJS5JM=1pQ>#QGr_mh4W0ojX~UbRf1-66}%nMO|GF zkvL+1+o66(hn#n1jyH}q$1%qqgbsRb#Ogr$659#usQJ)$9P}L&63;b6+mcVPCg50_ zH>t1xioVXV$8?=NjlRRN=D5h3-!qM?o;VD`)k@sjy3HL$C~4fW6gSa74~-z z?87}F_Q9-Qjy2aM9BZy0IMy6*3-IjtMLa{^U&tQcXO0VwHSGh(ns$d{%`yKOp3V1$ zzPm&8HTycpnthUENr%9eaICrBnTYzO^I5{qhcVYB97}Uyu>MVk4c65hYp%IYqkidm ze%SdirtRZc(?)Tuxt8NtbMI8Q#Kc%e4*N~gm-bGJurEx84eTVxnthUE&2<#*HE(;P zaQWNb7;9bc5c}P_QEq#z`#6@yJh4w<{g4bxYYp08aI9Hp>+9`}ti^tFWXOKgv{4*u z+CGjo$1%s6`)*nj4E{8K^v$Zxt?P9fZ?s3J{d_X4xo60!T(kdj<_f z4{MyHEs|k_Hs)Bfeyh~q8#{{r&@-ezm}?l0HTR|*YqlH5n)Y}0pjOqo zW4w*5+T6OoFzqDAn(LBe*udw=v1WgGquP?#X!uLom%G{O?=#0H$C`GMW6e6_SaU7+ zg=`kB-e*Kc^*#lx^=r-n980$PCtzo5WnmvVp&Z)4^QRzPqbLq|k<}j6xgi{&iZ@w!e0y+YbAdWY}PT z%(0}ygy)92k7B>cvD9~ntq-=XR~Ek~7NO51hz-`M9BZzBd+sU`%c&lSrFwv$Hpa2$ ze(2AAx4RcRT+F!G!5*({_DPO4bx4M#wxInc$D01W1N(0GE_Jw=dZ~l`9B*P@!Wh~E z{~5=UO??)11|5=OgY`OBuDR!(B%8$_?=vFx@jeBt^RYRGIM%$kWZ1yR&#|U2XfE`v z342yE#GVmLHfld?6vvvjBpEjFwQ;QJvzZF}TOajXKcs$%rTzeYBOGh4?UP}HX9pZ> z?%!zbiT^^+9H2Ri#__Z0lLr%HJ{7jl+INTz{9GJMI*fyjdPMv9bJD@wAN$(opf9oG zlPs6UTQG)NC+vFYy_sW^W6gT_D`C%4Vb4PAET~_OHTzC7Y~Z)&Skn*lOTwOIz@Ayx z59a*FvF6xJh7J7S9Bb|&$F=P1N<0tPU8jz9e{8O~IM!Utajdx?;#eIs?VtDB;Pe&o zbJ&66k3zurHjf6L{+Z-!&_Z?0T=*8s=rSZx1X%l{8sqCkOorDEG6bw6lg z)z{R4W6k#{aIAT@CdcaE==$%7__EsqukML5@i&)MuksC8m^fDdKEQup636OTOaEOj9BaN;V+Zsdh-X?AL-f_Z zG56boV|CoNUuPVv&pq(p{ll^5nVp#pcGPO{RI}&}C$F&9uh|wHYt|XZn(t)cSo7S_ zJa0Ty`=y(jM?YVc->R?qUKoze{%)Gq{hCM5RJNC!{oK%;So2*v-3RShLiJlbq<+ma zJ2_VWcG4dg9IN9<{r=0brrlW#`_Sk_nP~42`(Wz8v8E0jYuYo8HP1&Zi28l_sb=vK zA@yt8K8`hQ6vvwH58&ABXG*r{*F1h9q@U^YHU9hlfSlOu?*zz+&3xW-fOpL4vSwHCC5Bcvs<5-%zgZIL4 zto}{B|Nb|QHFYS7^~1@c+hPxgtRKudmSfGin`6y;<5;TS;5`2N0}I5PU;Zhz`DK26 z#M%TSv8{LX?@j%+GRNxQD*J2YWZ0m7IadGP)E{qMq3ks-j=6IJxX_sTo{=l(jKTC!U+RcN$_3=z=ONhQ^yK$`9794A~aWX8O2}SQP z*oppd63-07`h&S=;8=4n!m(z%aqOAAE8O({B_iqlr_8VUZNKPmo#s~gty6`Ftv?W3 zpw5X%fjY0Ib8PUNZF=W!GHmc35RTRQ#-MMNyP$7j=vz2MU(z9XZwbfhdyC=Ts&cHp zH~*bj9Bck=am=hf@m7si#13v>VXfaT{Z@F#kDQ1cKk{li#|FPCrusGC5n*e$;CGAk z4i1hb9j5+KA~N-lDf8Rx?i;^&Ia>AN<+xQ}QwKWJA$a$XO$YPdk|{Un4|JYF@Q$9a za-nYw`c`=w`u53+R_&7&u5ZvElGHbbwy2tnzP5KDh3Shn_RFOr zvB7VR=)J%68}s13Fg6{6GY9CMO&n{Ei%UcMMt45EGU6PMTKj`JE;u$gr-9z-#OgDzGVo76^g$D=zUG+@9IN*i{<(l0Yu+2jYM+8fXA{nc z|DitolLMDkub0le7Rj)9Kd*mp#KNB%hdeA+jd0so{`U(z8s|CeLUe#Wt8KjT>K@AJ=>)4sM0_$RIU zYX6SEPUTqb@AKEy982W}^~$B@%O``Y|7XF2vC zXVE46QRJVr>T9mgwBIO{)&3}d-N&)oALXAr&av9p=AZ3GzQN`R|D;u4vyC~{>^mH* zeS`kHJvi2EH}VZuNcbnM`kHOQv1Xldtl1wp)~sLcD<=P>RbR6nIM&=VaICo(;aKhO z`>%iUmCkeLztXuv%(g!c_ULpDC;1U`V$D4|$5Oe$xt1KO_5H7ZvO}l2^E-43*Ecwa zll+J|v0C5%`X_T@13wI%@ywN*-9HI`RBZe971sI<{D|4lQna;2;2Wg2FwZ=+v8HcO z`?*4O$nKv!d^wta_;TE;uURhn@N!~Jea$mmZTb=$^ao;tGiPnA*7v{u$wgVw^hH^A zeW~1_KahViID0p&+`y067WeiY>fyVPdeHY4%YLRWS1z^1Q}9pj4CxPMxzxtN*`>B} z1OFtw$A)9G`#p2g!5kOb*A^*oJZkL^+5L#{4TiFTf0EwK$dzl3H;y&mD|Zq8$)Dk$ zY#O4kX`?vSw0#^K_&wG0YMqr8y~+PPgX)$%6w8oRV|rT&?X&xPw7 zyeoq%*L;5fS1#S#_tT2T)+C{C<33q2(l;`{wpVv$p3L)|#$>*9I$Yo2y&6w4^=rN- zh%1-$oz;0yY&G=d%3XTJow1?NH&^?_`Sxqt4$6Eiq<+ma_TNWa6t37mEvzlFzb7cC za$iLok8aS;dkt;Om78{D(MX_gmmYc2hCMMRvvWxO_A}l!P!DafSr z?xSd9()Vt(F;{M@r_Mxz{=k)+{apjGwu92b+QNKS5mzp?@o?xXbsOhYZr87dyTN$t z(Rgg_7jEmH`FKcwFyCR&6>YKXi7{zmZDF3>&z0+#$Lf$Z6Ls56eGISb{| z{N}cSO%)BwSI3+cwastZPDW6!+ah6qQ^Q#Ou9pbj2gtH|zM%Py)q&(m8JO&@0;=U z<;tb`jr7GDhAmgyKEFS3q~ZhOJaVrvNXR1wE$8mT{Pu2Q zezWSJ*93ll;L0WYi?wG2?{s6!)oU2PKXB#h`GV#*cWz>SOT~O))tBbCV7$>hv@S8f zSy??_&^uw-a%p}G#v4~I=^NO-`=M`xwuNbav+6+e8`(3w#m`&W$S<0Ca|dght4w)rjWEZZt%wgzIOO0FFJS!`sInE%ql{>g$ zIbYvghiiKM>g3JL#Cj()WW5u1Rd58j)z4#a+pwjkC#d)HQO z*crrOtnEx+8%sJ&#+sJujOMHZca)4p*W2s2`ioabNM8qR?f3JfEgDfWvSN*$4Le`i zrbF0y#WwaX=s^1Bh7NcAmM1NaHjan1F|pKt>E6uqt8L|yzP59w!`PrdaOIK?)E`I( zPTw*&{_g8bw?_Q5sZ zDQ_z`?EUj$tnIz_HdfmxvJbAd52>g#t4-Bollp_(Ct)8_VIQol9`kgTxJ&1F_iK{r z|JL57gSI7fPCCny4(O9)AKd#B_90XUJvL+L>+YWF?W(Pp{@L82`eMvSaOStG&nVAP zUz~j&!`bI-xugTed<0|OU+;XDun$%p$Ub0f`t?ip;rE1nu(CAXNMEX7PG7PQq%YO) zy2Ls3sW^w;S}u(@(wFMDX2L$C!ajtu=}8FqXz~ z_O)jiYg=>K*s%4ajSX8X+t{#ufQ=2?tB*KeMq^ zF4>)SjD*#1n4im5ZkUhB#!|ZlbF8`Mvaw`!)XcY{tfhJyWx>q%X!$ z1Y^jf^@A*3GKTeowLj=}39aS+vDdSe8}{tW#_D2GpjU^py`(qm$_I%UE zQd`*k1U6Q$AO7{6*T#lD!?v;7p3&OV+XZ`8x~xB6SldF|9oh%{!w+LCH|)8;jn#JY zU$F-^R@?P|`L1lNw(I|jQ?RjAF4-Nb2h)FMW2xN0MwxL6HkQgIyFCnF-IsSDy;D>W6(K8%N}{r; zBC0}G6{$GLuezuKSwqwmcOfNNQ``-Cx2OeKOVk!=A|hN!S471#1@?LSDxL-UV z9)x^QJR}|#bwxeMdZNB)AR3BCARiHribmow(HOF^cw96QO+_=vW}>-x0x8MnqJ?-8 zDajV1C1gv{3bK`W3ZGV@HDqh?v}hyRigu9g#53Yq(Ox_U`J8xObPyfI3y?2}7x8&P zyaf4@cp0CU#4C`mh*!mHqLb(h*#&7A(bbpTkaiQ@ec1zPPti;ChU_g~7jK9@qAz4$ z(NFXj1H?ecf#OZ^mKY=kLk<>iiy>mD7zQ~U>2NW^mm`sm5+iXv8s8zvQ*JbJ??8^h z^*ds$|Ch12dPj`I)mX^!xEd?o#dkd97v!f$f;r)K2ycVkROZb;uECP#SHw*G~{PM&JZ(kH4Acv_!Qqykf+?I$jyfQ4A-;8 z=l)+l$JJ~x2Unj%&V`&S=HYLj`*NQ6LVPLai*(3zkpY>3!(zY0ccEA$z7mTe7mKgO z60uZdLS~AX@I+jE1Nn_uCYFm8VkP8C@vZnyd@oi(t`e)o8nITagItevjo5&6jo66v z2l1oW1i49U7F&>R7C#{+xfSUau?>IQhIBjRcCkbJ>|g(ktDWK(u}l04`K#D1_K3Y= zALKrCL`DNaG25~sx(@uxTo zc~+bge~G`vdC2qPg19IyiOZ0e1zZgBqA#kf}(k zK~{#Wj;HTPIiFoAUnzzkam4`f?c3!EzX`2g~6|N63+K6yzv5TD~L4$gz-P@YayrsaAg9V1ke@()B4^?|RnEfa zQ{-mJ*+@S_Iu-JBq;uq4IS+E4{6c;y=gV}+beSO+$c1td_WGCb!ES@@L4O2YM>gbM<5?X+6b}%Vve8>g&sXNc*b+ zY9Qo5^`?4D4N`+4-$ptF@-4`rNQXfVfgGZS<1+%e;c6t(k!qALMI2A0NGC&1g!~ZcN05^try!lGrm2r1KUUM#CrC+7S2NU1q$Fpk zS?W_YTYU!knfhGKQFGNi$a(4u^`)Ax(jn7ThFYK&szs2C)K_Y;`dTf4T%wk$Or#{2 zs+jVSl8mXi`bI5N%ORJm6>6pWR(%KgJDh!+M#}i{8{Z(zo=d6SIA%0Zna14Rr?_Ksr~AJI;ajo9#V(Z z5p`4@gFL4GqkdDrtK*Qz)d}?nQj#asNp%V-$u5yG!(n0DVO@T~ta^aKW$m<|)LV7dg zjgTdf-r|&WNPTxqR)egG^e*Rarxs)_r?!*kL>w2=b)wEaNJ&PWI?laFN!D@hbMAK@a2|ww z(0Ryt*s1H(gRJM&cN#biokt)aaUOLVIgdGwAsai7Bi96JQ(RHL8LpZl*BrSgkZ*x2 z%0G##7Ra?kt`+i6;fnIDarG2(Pb1d``L?*Cd^=pVMeZ5oo<+Vrt|BE6TrutCx{`6}i`t?}RJLcg9sGoM1=mxZY0k%x(~*9H^kd{^`1y~WnaIz=)u;HEnaIud^D~{#kpCQ4bMP;p zAvf30f9A|X{tH}viGP`g+%(q(3-6BmEKFPUL^V)lTGhA@{4F-{tIf_TX>3@!93< zh1~1x!(Vng`|;V0{C<27;ByeU1I{6&2O$qb9(Im6N0A=E=dg1O@|g1<{N;%A8$L&n z{|(>Yo#RMJ{_dP`{y<9dgmV(|q;m@L6m&f8oP|8=oWtj=^B2B< zL!QI;Jmh)j0^|kfBA9c&yy#p){*rSUWER*n$cdCJY-|2TdKt@~ESOiBl9J;1xm?IQ zDY;W};V*fR%Y!`0yh!sR%?Ft;B|pAb__6@fD^m*KxY z7KXeU@*1Q?APYklMOq}K7}6ps3aNlB0$BwAD)7BFh5R=3UyvrQ{wK+&6Z}WN=W63j RqPR$pe*Z-8c%zuk{{ukwBn$um literal 0 HcmV?d00001 diff --git a/Content/Common/Data/Quaternius/SurvivalPack/Prefabs/FirstAidKit.prefab b/Content/Common/Data/Quaternius/SurvivalPack/Prefabs/FirstAidKit.prefab new file mode 100644 index 0000000..1b0a750 --- /dev/null +++ b/Content/Common/Data/Quaternius/SurvivalPack/Prefabs/FirstAidKit.prefab @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content/Common/Data/Scenes/Inventory.scene b/Content/Common/Data/Scenes/Inventory.scene new file mode 100644 index 0000000..2dbd002 --- /dev/null +++ b/Content/Common/Data/Scenes/Inventory.scene @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content/Common/Data/Scenes/Sample.xml b/Content/Common/Data/Scenes/Sample.xml index 3d16151..c7fbad3 100644 --- a/Content/Common/Data/Scenes/Sample.xml +++ b/Content/Common/Data/Scenes/Sample.xml @@ -3,8 +3,8 @@ - - + + @@ -93,7 +93,7 @@ - + @@ -912,7 +912,7 @@ - + @@ -1191,20 +1191,10 @@ - + - - - - - - - - - - - - + + @@ -1236,4 +1226,16 @@ + + + + + + + + + + + + diff --git a/Content/Common/Data/UI/Inventory.rml b/Content/Common/Data/UI/Inventory.rml new file mode 100644 index 0000000..d4af874 --- /dev/null +++ b/Content/Common/Data/UI/Inventory.rml @@ -0,0 +1,35 @@ + + + + + + + +
+ Inventory items: {{ inventory_items.size }}
+
+ {{ item_value.name }} +
+
+ +
diff --git a/Directory.Build.props b/Directory.Build.props index fb07e1d..98d2a15 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 0.3.7.832 + 0.3.7.837 \ No newline at end of file diff --git a/RbfxTemplate/DoorButton.cs b/RbfxTemplate/DoorButton.cs index 7baf800..daaf5dc 100644 --- a/RbfxTemplate/DoorButton.cs +++ b/RbfxTemplate/DoorButton.cs @@ -71,7 +71,7 @@ public Animation CloseAnimation public override void Interact(Player player) { - var controller = Node.Parent.GetComponent(true); + var controller = Node.Parent.FindComponent(ComponentSearchFlag.Default); if (controller.NumAnimations > 0) return; diff --git a/RbfxTemplate/DoorTrigger.cs b/RbfxTemplate/DoorTrigger.cs index b1ad46c..4391baf 100644 --- a/RbfxTemplate/DoorTrigger.cs +++ b/RbfxTemplate/DoorTrigger.cs @@ -9,15 +9,15 @@ public DoorTrigger(Context context) : base(context) { } - [SerializeField(Mode = AttributeMode.AmDefault, Name = "Inventory Key")] - public string InventoryKey { get; set; } + [SerializeField(Mode = AttributeMode.AmDefault, Name = "Item Definition")] + public ResourceRef ItemDefinition { get; set; } = new ResourceRef(nameof(ItemDefinitionResource)); public override bool Filter(Node node) { - if (!string.IsNullOrEmpty(InventoryKey)) + if (ItemDefinition != null) { var player = node.GetComponent(); - if (player != null) return player.HasInInventory(InventoryKey); + if (player != null) return player.HasInInventory(ItemDefinition); return false; } diff --git a/RbfxTemplate/GameRmlUIComponent.cs b/RbfxTemplate/GameRmlUIComponent.cs index ad6bfa9..a1839d1 100644 --- a/RbfxTemplate/GameRmlUIComponent.cs +++ b/RbfxTemplate/GameRmlUIComponent.cs @@ -32,7 +32,7 @@ public RmlUIStateBase State private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { - DirtyVariable(e.PropertyName); + UpdateProperty(e.PropertyName); } public void UpdateProperties() @@ -40,6 +40,12 @@ public void UpdateProperties() DirtyAllVariables(); } + public void UpdateProperty(string propertyName) + { + if (!string.IsNullOrEmpty(propertyName)) + DirtyVariable(propertyName); + } + protected override void OnDataModelInitialized() { State?.OnDataModelInitialized(this); diff --git a/RbfxTemplate/GameSettings.cs b/RbfxTemplate/GameSettings.cs index d39fe27..a34893a 100644 --- a/RbfxTemplate/GameSettings.cs +++ b/RbfxTemplate/GameSettings.cs @@ -63,6 +63,9 @@ public void Apply(Context context) /// Render pipeline component. public void Apply(RenderPipeline renderPipeline) { + if (renderPipeline == null) + return; + renderPipeline.SetRenderPassEnabled("Postprocess: SSAO", SSAO); renderPipeline.SetRenderPassEnabled("Postprocess: Bloom", Bloom); renderPipeline.SetRenderPassEnabled("Postprocess: FXAA v3", FXAA); diff --git a/RbfxTemplate/GameState.cs b/RbfxTemplate/GameState.cs index 0efda51..531c67b 100644 --- a/RbfxTemplate/GameState.cs +++ b/RbfxTemplate/GameState.cs @@ -7,7 +7,6 @@ public partial class GameState : RmlUIStateBase { protected readonly SharedPtr _scene; protected readonly SharedPtr _cross; - private readonly UrhoPluginApplication _app; private readonly Node _cameraNode; private readonly Viewport _viewport; private readonly Node _character; @@ -18,6 +17,10 @@ public partial class GameState : RmlUIStateBase private bool _interactionEnabled = false; private bool _hasInteractable = false; private float _interactionProgress; + private readonly InputMap _inputMap; + private bool _inTransition = false; + + public Player Player => _player; public string InteractableTooltip { @@ -48,9 +51,8 @@ public GameState(UrhoPluginApplication app) : base(app, "UI/GameUI.rml") MouseMode = MouseMode.MmRelative; IsMouseVisible = false; - var inputMap = Context.ResourceCache.GetResource("Input/MoveAndOrbit.inputmap"); + _inputMap = Context.ResourceCache.GetResource("Input/MoveAndOrbit.inputmap"); - _app = app; _scene = Context.CreateObject(); _scene.Ptr.LoadXML("Scenes/Sample.xml"); @@ -67,7 +69,7 @@ public GameState(UrhoPluginApplication app) : base(app, "UI/GameUI.rml") .SetPrefab(Context.ResourceCache.GetResource("Models/Characters/YBot/YBot.prefab")); var character = SetupCharacter(_character); _player = _character.CreateComponent(); - _player.InputMap = inputMap; + _player.InputMap = _inputMap; _player.AttractionTarget = character.ModelPivot.CreateChild("AttractionTarget"); _player.AttractionTarget.Position = new Vector3(0, 1.0f, 1.0f); _player.AttractionTarget.CreateComponent(); @@ -78,9 +80,9 @@ public GameState(UrhoPluginApplication app) : base(app, "UI/GameUI.rml") cameraPrefab.SetPrefab( Context.ResourceCache.GetResource("Models/Characters/Camera.prefab")); cameraPrefab.Inline(PrefabInlineFlag.None); - _player.Camera = _character.GetComponent(true); + _player.Camera = _character.FindComponent(ComponentSearchFlag.Default); _cameraNode = _player.Camera.Node; - _character.CreateComponent().InputMap = inputMap; + _character.CreateComponent().InputMap = _inputMap; character.CameraYaw = _character.GetChild("CameraYawPivot", true); character.CameraPitch = _character.GetChild("CameraPitchPivot", true); character.CameraNode = _cameraNode; @@ -110,24 +112,37 @@ public override void OnDataModelInitialized(GameRmlUIComponent menuComponent) public override void Activate(StringVariantMap bundle) { - SubscribeToEvent(E.KeyUp, HandleKeyUp); - - _scene.Ptr.IsUpdateEnabled = true; - - _app.Settings.Apply(_scene.Ptr.GetComponent()); + Application.Settings.Apply(_scene.Ptr.GetComponent()); base.Activate(bundle); } - public override void Deactivate() + public override void TransitionStarted() { + _inTransition = true; + _scene.Ptr.IsUpdateEnabled = false; UnsubscribeFromEvent(E.KeyUp); + } + + public override void TransitionComplete() + { + _inTransition = false; + + SubscribeToEvent(E.KeyUp, HandleKeyUp); + _scene.Ptr.IsUpdateEnabled = true; + } + + public override void Deactivate() + { base.Deactivate(); } public override void Update(float timeStep) { + if (_inTransition) + return; + base.Update(timeStep); var interactable = _player.Interactable; @@ -138,6 +153,12 @@ public override void Update(float timeStep) InteractableTooltip = interactable.Tooltip ?? string.Empty; InteractionEnabled = interactable.InteractionEnabled; } + + if (_inputMap.Evaluate("Inventory") > 0.5f) + { + Application.OpenInventory(); + _scene.Ptr.IsUpdateEnabled = false; + } } protected override void Dispose(bool disposing) @@ -152,7 +173,7 @@ private Character SetupCharacter(Node _character) var player = _character.CreateComponent(); player.CharacterController = _character.GetComponent(); player.CameraCollisionMask = uint.MaxValue & ~player.CharacterController.CollisionLayer; - player.AnimationController = _character.GetComponent(true); + player.AnimationController = _character.FindComponent(ComponentSearchFlag.Default); player.ModelPivot = _character.GetChild("ModelPivot"); player.Idle = Context.ResourceCache.GetResource("Animations/Idle.ani"); //player.Idle = Context.ResourceCache.GetResource("Animations/CrouchIdle.ani"); @@ -170,7 +191,7 @@ private void HandleKeyUp(VariantMap args) { case Key.KeyEscape: case Key.KeyBackspace: - _app.HandleBackKey(); + Application.HandleBackKey(); return; } } diff --git a/RbfxTemplate/Inventory/ExtensionMethods.cs b/RbfxTemplate/Inventory/ExtensionMethods.cs new file mode 100644 index 0000000..3b8e5a0 --- /dev/null +++ b/RbfxTemplate/Inventory/ExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace RbfxTemplate.Inventory +{ + public static class ExtensionMethods + { + public static string GetName(this InventorySlot slot) + { + return slot?.ItemDefinition?.Value?.Name ?? string.Empty; + } + } +} \ No newline at end of file diff --git a/RbfxTemplate/InventoryItem.cs b/RbfxTemplate/Inventory/InventoryItem.cs similarity index 75% rename from RbfxTemplate/InventoryItem.cs rename to RbfxTemplate/Inventory/InventoryItem.cs index 2e84659..fafdcc1 100644 --- a/RbfxTemplate/InventoryItem.cs +++ b/RbfxTemplate/Inventory/InventoryItem.cs @@ -9,15 +9,15 @@ public InventoryItem(Context context) : base(context) { } - [SerializeField(Mode = AttributeMode.AmDefault, Name = "Inventory Key")] - public string InventoryKey { get; set; } = string.Empty; + [SerializeField(Mode = AttributeMode.AmDefault, Name = "Item Definition")] + public ResourceRef ItemDefinition { get; set; } = new ResourceRef(nameof(ItemDefinitionResource)); /// public override bool InteractionEnabled { get; } = true; public override void Interact(Player player) { - player.AddToInventory(InventoryKey); + player.AddToInventory(ItemDefinition); OnHoverEnd(player); Node.Remove(); } diff --git a/RbfxTemplate/Inventory/InventorySlot.cs b/RbfxTemplate/Inventory/InventorySlot.cs new file mode 100644 index 0000000..304f33e --- /dev/null +++ b/RbfxTemplate/Inventory/InventorySlot.cs @@ -0,0 +1,9 @@ +namespace RbfxTemplate.Inventory +{ + public class InventorySlot + { + public ItemDefinitionResource ItemDefinition { get; set; } + + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/RbfxTemplate/Inventory/ItemDefinition.cs b/RbfxTemplate/Inventory/ItemDefinition.cs new file mode 100644 index 0000000..35fc6ef --- /dev/null +++ b/RbfxTemplate/Inventory/ItemDefinition.cs @@ -0,0 +1,35 @@ +using System.Text.Json.Serialization; +using Urho3DNet; + +namespace RbfxTemplate.Inventory +{ + /// + /// Item definition stored in container serialized in json via . + /// + public class ItemDefinition + { + [JsonPropertyName("name")] + public string Name + { + get; set; + } + + [JsonPropertyName("icon")] + public ResourceRef Icon + { + get; set; + } + + [JsonPropertyName("prefab")] + public ResourceRef Prefab + { + get; set; + } + + [JsonPropertyName("weight")] + public float Weight + { + get; set; + } + } +} \ No newline at end of file diff --git a/RbfxTemplate/Inventory/ItemDefinitionResource.cs b/RbfxTemplate/Inventory/ItemDefinitionResource.cs new file mode 100644 index 0000000..b27c094 --- /dev/null +++ b/RbfxTemplate/Inventory/ItemDefinitionResource.cs @@ -0,0 +1,17 @@ +using RbfxTemplate.Inventory; +using RbfxTemplate.Utils; +using Urho3DNet; + +namespace RbfxTemplate +{ + /// + /// Resource container for ItemDefinition. + /// + [ObjectFactory] + public partial class ItemDefinitionResource: JsonResource + { + public ItemDefinitionResource(Context context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/RbfxTemplate/InventoryState.cs b/RbfxTemplate/InventoryState.cs new file mode 100644 index 0000000..7a764f1 --- /dev/null +++ b/RbfxTemplate/InventoryState.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using System.Linq; +using RbfxTemplate.Inventory; +using Urho3DNet; + +namespace RbfxTemplate +{ + [ObjectFactory] + public partial class InventoryState : RmlUIStateBase + { + protected readonly SharedPtr _scene; + private readonly Viewport _viewport; + + private List> _playerInventory = new List>(); + private VariantList _inventory = new VariantList(); + private readonly PrefabReference _prefabReference; + + public InventoryState(UrhoPluginApplication app) : base(app, "UI/Inventory.rml") + { + _scene = Context.CreateObject(); + _scene.Ptr.LoadXML("Scenes/Inventory.scene"); + _scene.Ptr.IsUpdateEnabled = false; + + var cameraNode = _scene.Ptr.FindComponent(ComponentSearchFlag.Default)?.Node; + + _prefabReference = _scene.Ptr.FindComponent(ComponentSearchFlag.Default); + + _viewport = Context.CreateObject(); + _viewport.Camera = cameraNode?.GetComponent(); + _viewport.Scene = _scene; + SetViewport(0, _viewport); + + } + + public override void OnDataModelInitialized(GameRmlUIComponent component) + { + component.BindDataModelVariantVector("inventory_items", _inventory); + } + + public override void Activate(StringVariantMap bundle) + { + Application.Settings.Apply(_scene.Ptr.GetComponent()); + + var player = Application.Game?.Player; + _playerInventory.Clear(); + _inventory.Clear(); + if (player != null) + { + _playerInventory.AddRange(player.Inventory.OrderBy(_ => _.Value.GetName())); + foreach (var inventorySlot in _playerInventory) + { + _inventory.Add(new VariantMap { { "key", inventorySlot.Key }, { "name", inventorySlot.Value.GetName()},{ "count", inventorySlot.Value.Count } }); + } + + if (_inventory.Count > 0) + { + Preview(0); + } + } + + base.Activate(bundle); + } + + private void Preview(int index) + { + if (_prefabReference == null) + return; + + _prefabReference.SetPrefab(null); + + if (index < 0 || index >= _inventory.Count) + return; + + var slot = _playerInventory[index].Value; + + var prefab = slot?.ItemDefinition?.Value?.Prefab; + if (prefab != null) + { + _prefabReference.SetPrefab(Context.ResourceCache.GetResource(prefab.Name)); + } + } + + public override void TransitionComplete() + { + SubscribeToEvent(E.KeyUp, HandleKeyUp); + } + + public override void TransitionStarted() + { + UnsubscribeFromEvent(E.KeyUp); + } + + public override void Deactivate() + { + base.Deactivate(); + } + + private void HandleKeyUp(VariantMap args) + { + var key = (Key)args[E.KeyUp.Key].Int; + switch (key) + { + case Key.KeyEscape: + case Key.KeyBackspace: + Application.HandleBackKey(); + return; + } + } + } +} \ No newline at end of file diff --git a/RbfxTemplate/Player.cs b/RbfxTemplate/Player.cs index 17f5e64..850c8c6 100644 --- a/RbfxTemplate/Player.cs +++ b/RbfxTemplate/Player.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.Linq; using RbfxTemplate.CharacterStates; +using RbfxTemplate.Inventory; using Urho3DNet; namespace RbfxTemplate @@ -9,7 +11,12 @@ public partial class Player : LogicComponent { private readonly PhysicsRaycastResult _raycastResult; - private readonly HashSet _inventory = new HashSet(); + private static readonly StringHash FieldNameResource = "Resource"; + private static readonly StringHash FieldNameCount = "Count"; + + private readonly Dictionary _inventory = new Dictionary(); + + //private readonly HashSet _inventory = new HashSet(); private bool _usePressed; private Node _selectedNode; private IInteractable _interactable; @@ -26,6 +33,11 @@ public Player(Context context) : base(context) _raycastResult = new PhysicsRaycastResult(); } + public IReadOnlyDictionary Inventory + { + get => _inventory; + } + public Camera Camera { get; set; } public Node SelectedNode @@ -47,7 +59,7 @@ public Node SelectedNode if (_selectedNode != null) { _interactable = _selectedNode.GetDerivedComponent() ?? - _selectedNode.GetParentDerivedComponent(); + _selectedNode.FindComponent(ComponentSearchFlag.SelfOrParentRecursive | ComponentSearchFlag.Derived); _interactable?.OnHoverStart(this); } @@ -156,14 +168,31 @@ private void CompleteInteraction() _interactable?.Interact(this); } - public void AddToInventory(string inventoryKey) + public void AddToInventory(ResourceRef inventoryKey) { - _inventory.Add(inventoryKey); + if (inventoryKey == null || string.IsNullOrEmpty(inventoryKey.Name)) + { + return; + } + + if (!_inventory.TryGetValue(inventoryKey.Name, out var inventorySlot)) + { + inventorySlot = new InventorySlot() + { ItemDefinition = Context.ResourceCache.GetResource(inventoryKey.Name) }; + _inventory.Add(inventoryKey.Name, inventorySlot); + } + + ++inventorySlot.Count; } - public bool HasInInventory(string inventoryKey) + public bool HasInInventory(ResourceRef inventoryKey) { - return _inventory.Contains(inventoryKey); + if (inventoryKey == null || string.IsNullOrEmpty(inventoryKey.Name)) + { + return false; + } + + return _inventory.ContainsKey(inventoryKey.Name); } public void GetIntoVehicle(Vehicle vehicle) diff --git a/RbfxTemplate/Selectable.cs b/RbfxTemplate/Selectable.cs index 79a37db..8d84ecc 100644 --- a/RbfxTemplate/Selectable.cs +++ b/RbfxTemplate/Selectable.cs @@ -28,7 +28,7 @@ public virtual void OnHoverStart(Player player) var outline = Scene.GetComponent(); if (outline != null) { - _drawables = Node.GetDerivedComponents(true); + _drawables = Node.FindComponents(ComponentSearchFlag.SelfOrChildrenRecursive | ComponentSearchFlag.Derived); foreach (var component in _drawables) { var drawable = component as Drawable; diff --git a/RbfxTemplate/StateStack.cs b/RbfxTemplate/StateStack.cs index fec27c6..8ad40ee 100644 --- a/RbfxTemplate/StateStack.cs +++ b/RbfxTemplate/StateStack.cs @@ -43,11 +43,14 @@ public StateStack(StateManager stateManager) /// Push state to the stack and make it current. /// /// State to push. - public void Push(ApplicationState state) + public void Push(ApplicationState state, StringVariantMap bundle = null) { if (state != null) { - _stateManager.EnqueueState(state); + if (bundle == null) + _stateManager.EnqueueState(state); + else + _stateManager.EnqueueState(state, bundle); _stack.Push(state); } } diff --git a/RbfxTemplate/UrhoPluginApplication.cs b/RbfxTemplate/UrhoPluginApplication.cs index 2857547..8653c16 100644 --- a/RbfxTemplate/UrhoPluginApplication.cs +++ b/RbfxTemplate/UrhoPluginApplication.cs @@ -14,6 +14,11 @@ public partial class UrhoPluginApplication : PluginApplication /// private SharedPtr _gameState; + /// + /// Inventory application state. + /// + private SharedPtr _inventoryState; + /// /// Safe pointer to menu screen. /// @@ -46,6 +51,11 @@ public UrhoPluginApplication(Context context) : base(context) /// public bool IsGameRunning => _gameState; + /// + /// Current game state or null if no game is running. + /// + public GameState Game => _gameState.Ptr; + protected override void Load() { Context.RegisterFactories(GetType().Assembly); @@ -94,7 +104,6 @@ protected override void Start(bool isMain) stateManager.EnqueueState(splash); } - // Crate end enqueue main menu screen. _stateStack.Push(_mainMenuState); @@ -105,6 +114,7 @@ protected override void Stop() { _mainMenuState?.Dispose(); _gameState?.Dispose(); + _inventoryState?.Dispose(); base.Stop(); } @@ -167,5 +177,11 @@ public void ResetSettings() _settings?.Dispose(); _settings = ConfigFileContainer.LoadConfig(Context); } + + public void OpenInventory() + { + _inventoryState = _inventoryState ?? new SharedPtr(new InventoryState(this)); + _stateStack.Push(_inventoryState); + } } } \ No newline at end of file