Initial commit of Access Control mod
This commit is contained in:
commit
8edebea402
20 changed files with 1507 additions and 0 deletions
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#Autosave files
|
||||
*~
|
||||
|
||||
#build
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
packages/
|
||||
TestResults/
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.DS_Store
|
||||
*.sln.cache
|
||||
*.suo
|
||||
*.cache
|
||||
*.pidb
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.log
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.user
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
Thumbs.db
|
||||
|
||||
#Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
#resharper
|
||||
*_Resharper.*
|
||||
*.Resharper
|
||||
|
||||
#dotCover
|
||||
*.dotCover
|
||||
369
AccessControls/AccessControlMod.cs
Normal file
369
AccessControls/AccessControlMod.cs
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
using Vintagestory.API.Client;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Datastructures;
|
||||
using Vintagestory.API.MathTools;
|
||||
using Vintagestory.API.Server;
|
||||
using Vintagestory.API.Util;
|
||||
using Vintagestory.GameContent;
|
||||
using Vintagestory.Server;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public class AccessControlsMod: ModSystem
|
||||
{
|
||||
private const string _AccessControlNodesKey = @"ACCESS_CONTROL_NODES";
|
||||
public const string _KeyIDKey = @"key_id";//for JSON attribute, DB key sequence
|
||||
public const string _persistedStateKey = @"ACL_PersistedState";
|
||||
|
||||
private ICoreServerAPI ServerAPI;
|
||||
private ICoreAPI CoreAPI;
|
||||
private ICoreClientAPI ClientAPI;
|
||||
private PlayerDataManager PlayerDatamanager;
|
||||
|
||||
private ModSystemBlockReinforcement brs;
|
||||
|
||||
private SortedDictionary<long, ChunkACNodes> Server_ACN;//Track changes - and commit every ## minutes, in addition to server shutdown data-storage, chunk unloads
|
||||
private Dictionary<BlockPos, LockStatus> Client_LockLookup;//By BlockPos - for fast cached lookup. only hold 100's of entries
|
||||
private ACLPersisted PersistedState;
|
||||
|
||||
private Item KeyItem;
|
||||
private Item CombolockItem;
|
||||
private Item UndeployedKeylockItem;//Key & Lock together
|
||||
private Item DeployedKeylockItem;
|
||||
|
||||
#region Mod System
|
||||
public override bool ShouldLoad(EnumAppSide forSide)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Start(ICoreAPI api)
|
||||
{
|
||||
this.CoreAPI = api;
|
||||
base.Start(api);
|
||||
}
|
||||
|
||||
public override void StartClientSide(ICoreClientAPI api)
|
||||
{
|
||||
this.ClientAPI = api;
|
||||
base.StartClientSide(api);
|
||||
}
|
||||
|
||||
|
||||
public override void StartServerSide(ICoreServerAPI api)
|
||||
{
|
||||
this.ServerAPI = api;
|
||||
this.PlayerDatamanager = api.Permissions as PlayerDataManager;
|
||||
base.StartServerSide(api);
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/*
|
||||
// Client side data
|
||||
Dictionary<long, Dictionary<int, BlockReinforcement>> reinforcementsByChunk = new Dictionary<long, Dictionary<int, BlockReinforcement>>();
|
||||
|
||||
Dictionary<ChunkPos, Dictionary<BlockPos, BlockReinforcement>>
|
||||
|
||||
clientChannel = api.Network
|
||||
.RegisterChannel("blockreinforcement")
|
||||
.RegisterMessageType(typeof(ChunkReinforcementData))
|
||||
.SetMessageHandler<ChunkReinforcementData>(onData)
|
||||
|
||||
data = chunk.GetModdata("reinforcements");
|
||||
|
||||
Dictionary<int, BlockReinforcement> reinforcmentsOfChunk = null;
|
||||
|
||||
reinforcmentsOfChunk = SerializerUtil.Deserialize<Dictionary<int, BlockReinforcement>>(data);
|
||||
*/
|
||||
|
||||
#region Access Control Interface
|
||||
|
||||
//Pull data out of BRS first - or intercept its channel packets?
|
||||
//Then superceed it 100% ?
|
||||
|
||||
public LockStatus LockState(BlockPos pos, IPlayer forPlayer)
|
||||
{
|
||||
if (CoreAPI.Side == EnumAppSide.Client)
|
||||
{
|
||||
if (Client_LockLookup.ContainsKey(pos.Copy( )))
|
||||
{
|
||||
return Client_LockLookup[pos.Copy( )];
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateLocalLockCache(pos );//Needs to be invoked each time keys change in inventory?!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Server instance
|
||||
|
||||
}
|
||||
|
||||
return LockStatus.None;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Backwardsy compatible method - for lockable behaviors
|
||||
/// </summary>
|
||||
/// <returns>when locked.</returns>
|
||||
/// <param name="position">Position.</param>
|
||||
/// <param name="player">Player.</param>
|
||||
/// <param name="code">Code.</param>
|
||||
public bool LockedForPlayer(BlockPos position, IPlayer forPlayer, AssetLocation code)
|
||||
{
|
||||
if (brs.IsLocked(position, forPlayer)) //Replace with local cache?
|
||||
{
|
||||
var controlNode = RetrieveACN(position.Copy( ));
|
||||
|
||||
if (controlNode.LockStyle == LockKinds.Classic || controlNode.LockStyle == LockKinds.Combination) {
|
||||
//Is it yours?
|
||||
if (controlNode.OwnerPlayerUID == forPlayer.PlayerUID) return false;
|
||||
|
||||
//In same faction?
|
||||
if (controlNode.PermittedPlayers != null & controlNode.PermittedPlayers.Count > 0) {
|
||||
|
||||
foreach (var perp in controlNode.PermittedPlayers) {
|
||||
if (perp.PlayerUID == forPlayer.PlayerUID) {
|
||||
return false;//By discreet entry - combo's add these
|
||||
}
|
||||
|
||||
if (perp.GroupID.HasValue) {
|
||||
PlayerGroup targetGroup = PlayerDatamanager.PlayerGroupsById[perp.GroupID.Value];
|
||||
if (PlayerDatamanager.PlayerDataByUid.ContainsKey(forPlayer.PlayerUID)) {
|
||||
ServerPlayerData theirGroup = PlayerDatamanager.PlayerDataByUid[forPlayer.PlayerUID];
|
||||
|
||||
if (theirGroup.PlayerGroupMemberships.ContainsKey(perp.GroupID.Value)) {
|
||||
return false;//Is member of group, thus granted.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true; //Locked BY DEFAULT: [Classic-lock] or [Combo-locks]
|
||||
} else if (controlNode.LockStyle == LockKinds.Key) //************** End of: Classic / Combination LOCKS ***********
|
||||
{
|
||||
//Search inventory for matching KeyID item...each time!
|
||||
foreach (var inventory in forPlayer.InventoryManager.Inventories)
|
||||
{
|
||||
IInventory actual = inventory.Value;
|
||||
foreach (ItemSlot itmSlot in actual)
|
||||
{
|
||||
if (itmSlot.Empty == false && itmSlot.Itemstack.Class == EnumItemClass.Item)
|
||||
{
|
||||
if (itmSlot.Itemstack.Item.ItemId == KeyItem.ItemId)
|
||||
{
|
||||
//The right key?
|
||||
var tempKey = itmSlot.Itemstack.Item;
|
||||
if (tempKey.Attributes.KeyExists(_KeyIDKey))
|
||||
{
|
||||
int tempKeyId = tempKey.Attributes[_KeyIDKey].AsInt(-1);
|
||||
if (tempKeyId == controlNode.KeyID.Value)
|
||||
{
|
||||
return false;//Key works in lock
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}//************** End of: KEY LOCKS ***********
|
||||
|
||||
|
||||
}
|
||||
|
||||
return false;//No lock here!
|
||||
}
|
||||
|
||||
public bool LockedForPlayer(BlockPos position, IPlayer forPlayer)
|
||||
{
|
||||
var aclNode = RetrieveACN(position);
|
||||
|
||||
if (aclNode != null)
|
||||
{
|
||||
if (aclNode.LockStyle == LockKinds.Key)
|
||||
{
|
||||
//Check player Inventory for Keys... do they have a key for THIS lock?
|
||||
var matchingKeyID = aclNode.KeyID.HasValue ? aclNode.KeyID.Value : 0;
|
||||
|
||||
|
||||
foreach (IInventory item in forPlayer.InventoryManager.Inventories.Values)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (aclNode.LockStyle == LockKinds.Combination)
|
||||
{
|
||||
//Check lock if AccessControlNode.PermittedPlayers.PlayerUID is present?
|
||||
|
||||
}
|
||||
|
||||
if (aclNode.LockStyle == LockKinds.Classic)
|
||||
{
|
||||
return !(aclNode.OwnerPlayerUID == forPlayer.PlayerUID);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void ApplyLock(BlockSelection blockSel, IPlayer player, ItemSlot lockSource)
|
||||
{
|
||||
//Log it alot!
|
||||
|
||||
GenericLock theLock = lockSource.Itemstack.Item as GenericLock;
|
||||
|
||||
|
||||
if (theLock.LockStyle == LockKinds.Combination) {
|
||||
|
||||
}
|
||||
|
||||
if (theLock.LockStyle == LockKinds.Key) {
|
||||
//keyCode.HasValue
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void AlterLockAt(BlockSelection blockSel, IPlayer player, LockKinds lockType, byte[] combinationCode = null, uint? keyCode = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void UpdateLocalLockCache(BlockPos pos)
|
||||
{
|
||||
throw new NotImplementedException( );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the ACN data
|
||||
/// </summary>
|
||||
/// <returns> Access Control node for a BlocKPos.</returns>
|
||||
/// <param name="byBlockPos">By block position.</param>
|
||||
public AccessControlNode RetrieveACN(BlockPos byBlockPos)
|
||||
{
|
||||
long chunkIndex = ServerAPI.World.BulkBlockAccessor.ToChunkIndex3D(byBlockPos);
|
||||
AccessControlNode node = new AccessControlNode( );
|
||||
|
||||
if (this.Server_ACN.ContainsKey(chunkIndex)) {
|
||||
|
||||
|
||||
if (Server_ACN[chunkIndex].Entries.TryGetValue(byBlockPos, out node))
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
} else
|
||||
{
|
||||
//Retrieve and add to local cache
|
||||
IServerChunk targetChunk;
|
||||
byte[] data;
|
||||
|
||||
if (ServerAPI.WorldManager.AllLoadedChunks.TryGetValue(chunkIndex, out targetChunk)) {
|
||||
data = targetChunk.GetServerModdata(_AccessControlNodesKey);
|
||||
|
||||
|
||||
} else
|
||||
{
|
||||
//An unloaded chunk huh...
|
||||
targetChunk = ServerAPI.WorldManager.GetChunk(byBlockPos);
|
||||
data = targetChunk.GetServerModdata(_AccessControlNodesKey);
|
||||
|
||||
}
|
||||
|
||||
if (data != null && data.Length > 0) {
|
||||
|
||||
ChunkACNodes acNodes = SerializerUtil.Deserialize<ChunkACNodes>(data);
|
||||
|
||||
Server_ACN.Add(chunkIndex, acNodes);
|
||||
|
||||
acNodes.Entries.TryGetValue(byBlockPos, out node);
|
||||
|
||||
} else
|
||||
{
|
||||
//Setup new AC Node list for this chunk.
|
||||
ChunkACNodes newAcNodes = new ChunkACNodes( );
|
||||
|
||||
Server_ACN.Add(chunkIndex, newAcNodes);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// byte[] GetServerModdata (string key);
|
||||
//void SetServerModdata(string key, byte[] data);
|
||||
|
||||
//public byte[] GetData(string name)
|
||||
//public void StoreData(string name, byte[] value)
|
||||
|
||||
//_oAzFHaLM7aeBn6i00bHS72XxcA9 ISaveGame
|
||||
|
||||
internal int NextKeyID
|
||||
{
|
||||
get { return ++PersistedState.KeyId_Sequence;}
|
||||
}
|
||||
|
||||
public bool AttemptAccess( IPlayer byPlayer, BlockPos atPosition, byte[] guess = null )
|
||||
{
|
||||
var acn = RetrieveACN(atPosition);
|
||||
|
||||
if (acn.LockStyle == LockKinds.Combination)
|
||||
{
|
||||
|
||||
} else
|
||||
{
|
||||
Mod.Logger.Warning("Attempt to access with mis-matching lock types! BY: {0}", byPlayer.PlayerName);
|
||||
}
|
||||
|
||||
return false;//Not it.
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
private void Initialize( )
|
||||
{
|
||||
var rawBytes = ServerAPI.WorldManager.SaveGame.GetData(_persistedStateKey);
|
||||
if (rawBytes != null && rawBytes.Length > 0)
|
||||
{
|
||||
this.PersistedState = SerializerUtil.Deserialize<ACLPersisted>(rawBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
ACLPersisted newPersistedState = new ACLPersisted( );
|
||||
|
||||
var aclPersistBytes = SerializerUtil.Serialize<ACLPersisted>(newPersistedState);
|
||||
|
||||
ServerAPI.WorldManager.SaveGame.StoreData(_persistedStateKey, aclPersistBytes);
|
||||
|
||||
this.PersistedState = newPersistedState;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
96
AccessControls/AccessControls.csproj
Normal file
96
AccessControls/AccessControls.csproj
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{180853A2-7E1D-4876-9D1E-AA8608D701C3}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>FirstMachineAge</RootNamespace>
|
||||
<AssemblyName>AccessControls</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="VintagestoryAPI">
|
||||
<HintPath>..\FirstMachineAge_Common\vs_libs\VintagestoryAPI.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VSEssentials">
|
||||
<HintPath>..\FirstMachineAge_Common\vs_libs\VSEssentials.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VSCreativeMod">
|
||||
<HintPath>..\FirstMachineAge_Common\vs_libs\VSCreativeMod.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VSSurvivalMod">
|
||||
<HintPath>..\FirstMachineAge_Common\vs_libs\VSSurvivalMod.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="protobuf-net">
|
||||
<HintPath>..\FirstMachineAge_Common\vs_libs\protobuf-net.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VintagestoryLib">
|
||||
<HintPath>..\FirstMachineAge_Common\vs_libs\VintagestoryLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AccessControlMod.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="behaviors\BlockBehaviorComplexLockable.cs" />
|
||||
<Compile Include="GUIs\GuiDialog_ComboLock.cs" />
|
||||
<Compile Include="items\ItemCombolock.cs" />
|
||||
<Compile Include="LocksmithCmd.cs" />
|
||||
<Compile Include="GroupLocksCmd.cs" />
|
||||
<Compile Include="items\GenericLock.cs" />
|
||||
<Compile Include="items\GenericKey.cs" />
|
||||
<Compile Include="data\AccessControlNode.cs" />
|
||||
<Compile Include="data\LockStatus.cs" />
|
||||
<Compile Include="data\LockKinds.cs" />
|
||||
<Compile Include="data\ACLPersisted.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="assets\" />
|
||||
<Folder Include="assets\fma\" />
|
||||
<Folder Include="assets\fma\itemtypes\" />
|
||||
<Folder Include="assets\fma\itemtypes\locks\" />
|
||||
<Folder Include="items\" />
|
||||
<Folder Include="behaviors\" />
|
||||
<Folder Include="GUIs\" />
|
||||
<Folder Include="assets\fma\shapes\" />
|
||||
<Folder Include="assets\fma\shapes\access_controls\" />
|
||||
<Folder Include="data\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="assets\fma\itemtypes\locks\combolock.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FirstMachineAge_Common\Common.csproj">
|
||||
<Project>{DE0A4E7D-E5FA-441D-A11A-8279E6AC5BBC}</Project>
|
||||
<Name>Common</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
25
AccessControls/GUIs/GuiDialog_ComboLock.cs
Normal file
25
AccessControls/GUIs/GuiDialog_ComboLock.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
|
||||
using Vintagestory.API.Client;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public class GuiDialog_ComboLock : GuiDialog
|
||||
{
|
||||
private ICoreClientAPI ClientAPI;
|
||||
|
||||
|
||||
public GuiDialog_ComboLock(ICoreClientAPI capi) : base(capi)
|
||||
{
|
||||
ClientAPI = capi;
|
||||
|
||||
}
|
||||
|
||||
public override string ToggleKeyCombinationCode {
|
||||
get {
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
AccessControls/GroupLocksCmd.cs
Normal file
25
AccessControls/GroupLocksCmd.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.MathTools;
|
||||
using Vintagestory.API.Server;
|
||||
using Vintagestory.API.Util;
|
||||
using Vintagestory.GameContent;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public class GroupLocksCmd: ServerChatCommand
|
||||
{
|
||||
public GroupLocksCmd( )
|
||||
//What about Clan/Faction leaders - for shared combos?
|
||||
{
|
||||
this.Command = "grouplocks";
|
||||
this.Description = "Change lock permissions and assigend groupIDs.";
|
||||
//this.handler += LocksmithParser;
|
||||
this.Syntax = "grant [group/player] [player-name/group-name] / revoke [group/player] [player-name/group-name]";
|
||||
//this.RequiredPrivilege = "locksmith";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
32
AccessControls/LocksmithCmd.cs
Normal file
32
AccessControls/LocksmithCmd.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.MathTools;
|
||||
using Vintagestory.API.Server;
|
||||
using Vintagestory.API.Util;
|
||||
using Vintagestory.GameContent;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public class LocksmithCmd : ServerChatCommand
|
||||
{
|
||||
private ICoreServerAPI ServerAPI;
|
||||
|
||||
public LocksmithCmd( )
|
||||
{
|
||||
this.Command = "locksmith";
|
||||
this.Description = "ALTER LOCKS: Remove or Change keys and combos.";
|
||||
this.handler += LocksmithParser;
|
||||
this.Syntax = "remove / change / downgrade / info ";
|
||||
this.RequiredPrivilege = "locksmith";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void LocksmithParser(IServerPlayer player, int groupId, CmdArgs args)
|
||||
{
|
||||
throw new NotImplementedException( );
|
||||
}
|
||||
}
|
||||
}
|
||||
27
AccessControls/Properties/AssemblyInfo.cs
Normal file
27
AccessControls/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("AccessControls")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("Melchior")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
|
||||
37
AccessControls/assets/fma/itemtypes/locks/combolock.json
Normal file
37
AccessControls/assets/fma/itemtypes/locks/combolock.json
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
code: "combolock",
|
||||
class: "ItemPadlock",
|
||||
maxstacksize: 64,
|
||||
variantgroups: [
|
||||
{ code: "material", states: ["tinbronze", "blackbronze", "bismuthbronze", "iron", "steel" ] },
|
||||
],
|
||||
textures: {
|
||||
"material": { base: "item/tool/material/{material}" }
|
||||
},
|
||||
shape: { base: "item/tool/padlock" },
|
||||
creativeinventory: { "general": ["*"], "items": ["*"] },
|
||||
guiTransform: {
|
||||
translation: { x: 4, y: 0, z: 0 },
|
||||
rotation: { x: 20, y: 16, z: -152 },
|
||||
origin: { x: 0.5, y: 0.12, z: 0.5 },
|
||||
scale: 6
|
||||
},
|
||||
groundTransform: {
|
||||
translation: { x: 0, y: 0, z: 0 },
|
||||
rotation: { x: -90, y: 0, z: 0 },
|
||||
origin: { x: 0.5, y: 0.2, z: 0.46 },
|
||||
scale: 3.5
|
||||
},
|
||||
fpHandTransform: {
|
||||
translation: { x: 0, y: 0, z: 0 },
|
||||
rotation: { x: -14, y: -78, z: 17 },
|
||||
origin: { x: 0.5, y: 0.1, z: 0.5 },
|
||||
scale: 2.41
|
||||
},
|
||||
tpHandTransform: {
|
||||
translation: { x: -0.83, y: -0.36, z: -0.7 },
|
||||
rotation: { x: 1, y: 57, z: 18 },
|
||||
origin: { x: 0.5, y: 0.15, z: 0.5 },
|
||||
scale: 0.65
|
||||
}
|
||||
}
|
||||
73
AccessControls/behaviors/BlockBehaviorComplexLockable.cs
Normal file
73
AccessControls/behaviors/BlockBehaviorComplexLockable.cs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
|
||||
using Vintagestory.API.Client;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Config;
|
||||
using Vintagestory.GameContent;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Multi-use Lockable behavior for combo/key/other locks
|
||||
/// </summary>
|
||||
/// <remarks>Replaces the old behavior...</remarks>
|
||||
public class BlockBehaviorComplexLockable : BlockBehaviorLockable
|
||||
{
|
||||
private AccessControlsMod acm;
|
||||
|
||||
public BlockBehaviorComplexLockable(Block block) : base(block)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel, ref EnumHandling handling)
|
||||
{
|
||||
LockStatus lockState = acm.LockState(blockSel.Position, byPlayer);
|
||||
|
||||
if (acm.LockedForPlayer(blockSel.Position, byPlayer)) //Checks for keys and known combos, ect...
|
||||
{
|
||||
if (world.Side == EnumAppSide.Client)
|
||||
{
|
||||
ICoreClientAPI clientAPI = (world.Api as ICoreClientAPI);
|
||||
|
||||
switch (lockState)
|
||||
{
|
||||
case LockStatus.ComboUnknown:
|
||||
//Does Not already know combo...
|
||||
ShowComboLockGUI(world, byPlayer,blockSel);
|
||||
|
||||
break;
|
||||
|
||||
case LockStatus.KeyHave:
|
||||
clientAPI.TriggerChatMessage("opened with a key...");
|
||||
handling = EnumHandling.PassThrough;
|
||||
return true;
|
||||
|
||||
case LockStatus.KeyNope:
|
||||
//Did not have key...
|
||||
clientAPI.TriggerIngameError(this, "locked", Lang.Get("ingameerror-nokey", new object[0]));
|
||||
break;
|
||||
|
||||
default:
|
||||
//Normal or 'default' lock:
|
||||
clientAPI.TriggerIngameError(this, "locked", Lang.Get("ingameerror-locked", new object[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handling = EnumHandling.PreventSubsequent;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return base.OnBlockInteractStart(world, byPlayer, blockSel, ref handling);
|
||||
}
|
||||
|
||||
protected void ShowComboLockGUI(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel)
|
||||
{
|
||||
throw new NotImplementedException( );
|
||||
}
|
||||
}
|
||||
}
|
||||
21
AccessControls/data/ACLPersisted.cs
Normal file
21
AccessControls/data/ACLPersisted.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using Vintagestory.API.MathTools;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
[ProtoContract]
|
||||
public class ACLPersisted
|
||||
{
|
||||
[ProtoMember(0)]
|
||||
public int KeyId_Sequence;
|
||||
|
||||
//Stats, other info?
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
107
AccessControls/data/AccessControlNode.cs
Normal file
107
AccessControls/data/AccessControlNode.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using Vintagestory.API.MathTools;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Holds individual Access control entries for that Chunk
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// (by block Position)
|
||||
/// </remarks>
|
||||
[ProtoContract]
|
||||
public class ChunkACNodes
|
||||
{
|
||||
public ChunkACNodes( )
|
||||
{
|
||||
Entries = new SortedDictionary<BlockPos, AccessControlNode>( );//SET Comparer?
|
||||
}
|
||||
|
||||
[ProtoMember(0)]
|
||||
public Vec3i OriginChunk;
|
||||
|
||||
[ProtoMember(1)]
|
||||
public SortedDictionary<BlockPos, AccessControlNode> Entries;//CHECK: does it *NEED* to be sorted?
|
||||
|
||||
//Last update DateTime?
|
||||
}
|
||||
|
||||
|
||||
[ProtoContract]
|
||||
public class AccessControlNode
|
||||
{
|
||||
public AccessControlNode( )
|
||||
{
|
||||
LockStyle = LockKinds.None;
|
||||
}
|
||||
|
||||
[ProtoMember(0)]
|
||||
public string OwnerPlayerUID;
|
||||
|
||||
[ProtoMember(1, IsRequired = true)]
|
||||
public LockKinds LockStyle;
|
||||
|
||||
[ProtoMember(2)]
|
||||
public string SourceItemName;
|
||||
|
||||
[ProtoMember(3)]
|
||||
public byte[] CombinationCode;//Nullable
|
||||
|
||||
[ProtoMember(4)]
|
||||
public int? KeyID;
|
||||
|
||||
[ProtoMember(5)]
|
||||
public List<AccessEntry> PermittedPlayers;//Also nullable - key locks should NEVER have entries here!
|
||||
|
||||
[ProtoMember(6)]
|
||||
public bool LockDefeated;//Ya Picked it; Taffer!
|
||||
|
||||
//public BlockPos Origin ; //Placement of lock in world (on block)
|
||||
|
||||
}
|
||||
|
||||
|
||||
[ProtoContract]
|
||||
public class AccessEntry
|
||||
{
|
||||
[ProtoMember(0)]
|
||||
public string PlayerUID;
|
||||
|
||||
//Access type; Player or Group ?
|
||||
|
||||
[ProtoMember(1)]
|
||||
public int? GroupID;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A Chunk's, Lock status list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used client-side for fast lookup
|
||||
/// </remarks>
|
||||
[ProtoContract]
|
||||
public class LockStatusList
|
||||
{
|
||||
[ProtoMember(0)]
|
||||
public Dictionary<BlockPos,LockStatus> LockStatesByBlockPos;
|
||||
|
||||
[ProtoMember(1)]
|
||||
public Vec3i ChunkOrigin;
|
||||
|
||||
|
||||
|
||||
//Last RX time for Cache-TTL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
18
AccessControls/data/LockKinds.cs
Normal file
18
AccessControls/data/LockKinds.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
[DefaultValue(LockKinds.None)]
|
||||
public enum LockKinds : byte
|
||||
{
|
||||
None, //No lock here!
|
||||
Classic,//Magic locks which open for their 'owner'
|
||||
Combination,//Mechanical locks that need manual input entry of a number or sequence to operate
|
||||
Key,//Mech. locks which need a specific item in inventory to open
|
||||
//Group,//ACL controlled lock, for Factions?
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
19
AccessControls/data/LockStatus.cs
Normal file
19
AccessControls/data/LockStatus.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
[DefaultValue(LockStatus.None)]
|
||||
public enum LockStatus : byte
|
||||
{
|
||||
None,//Do nothing = 'no lock here'.
|
||||
Locked,//Old behavior
|
||||
ComboUnknown,//GUI
|
||||
ComboKnown,//GUI prefilled?
|
||||
KeyHave,//Message?
|
||||
KeyNope,//Message!
|
||||
Unknown, //for cache non-update state? - e.g. LAG while updating.
|
||||
}
|
||||
}
|
||||
|
||||
31
AccessControls/items/GenericKey.cs
Normal file
31
AccessControls/items/GenericKey.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
|
||||
using Vintagestory.API.Common;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public abstract class GenericKey : Item
|
||||
{
|
||||
private const string _keyIdKey = @"key_id";
|
||||
|
||||
public uint KeyID {
|
||||
get {
|
||||
if (this.Attributes.Exists && this.Attributes.KeyExists(_keyIdKey)) {
|
||||
uint keyId = ( uint )this.Attributes[_keyIdKey].AsInt(0);
|
||||
|
||||
return keyId;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Attributes to -> AccessControlNode
|
||||
//Copy keyID, owner?
|
||||
|
||||
//itemstack.Collectible.Attributes[_keyIdKey].AsInt(null);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
148
AccessControls/items/GenericLock.cs
Normal file
148
AccessControls/items/GenericLock.cs
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
|
||||
using Vintagestory.API.Client;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Datastructures;
|
||||
using Vintagestory.API.Server;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public abstract class GenericLock : Item
|
||||
{
|
||||
private const string _lockStyleKey = @"lock-style";
|
||||
private const string _comboKey = @"combo";
|
||||
private const string _lockTier = @"lock-tier";
|
||||
private const uint MinimumComboDigits = 2;
|
||||
|
||||
protected ICoreServerAPI ServerAPI { get; set; }
|
||||
protected ILogger Logger { get; set; }
|
||||
protected ICoreClientAPI ClientAPI { get; set; }
|
||||
protected AccessControlsMod AccessControlsMod { get; set; }
|
||||
|
||||
public LockKinds LockStyle { get; protected set;}
|
||||
|
||||
public uint LockTier { get; protected set; }
|
||||
|
||||
public byte[] CombinationCode { get; protected set; }
|
||||
|
||||
public uint? KeyID { get; protected set; }
|
||||
|
||||
|
||||
public override void OnLoaded(ICoreAPI api)
|
||||
{
|
||||
base.OnLoaded(api);
|
||||
|
||||
if (api.Side.IsServer( )) {
|
||||
this.ServerAPI = ( ICoreServerAPI )api;
|
||||
this.Logger = this.ServerAPI.World.Logger;
|
||||
AccessControlsMod = ServerAPI.World.Api.ModLoader.GetModSystem<AccessControlsMod>( );
|
||||
}
|
||||
|
||||
if (api.Side.IsClient( )) {
|
||||
this.ClientAPI = ( ICoreClientAPI )api;
|
||||
this.Logger = this.ClientAPI.World.Logger;
|
||||
AccessControlsMod = ClientAPI.World.Api.ModLoader.GetModSystem<AccessControlsMod>( );
|
||||
}
|
||||
|
||||
Logger.VerboseDebug("{0} ~ OnLoaded", base.Code.ToString());
|
||||
|
||||
if (this.Attributes.Exists && this.Attributes.KeyExists(_lockStyleKey)) {
|
||||
this.LockStyle = this.Attributes[_lockStyleKey].AsObject<LockKinds>(LockKinds.None);
|
||||
}
|
||||
|
||||
if (LockStyle != LockKinds.None && this.Attributes.KeyExists(_lockTier))
|
||||
{
|
||||
this.LockTier = ( uint )this.Attributes[_lockTier].AsInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
//or? OnCreatedByCrafting -- generate keyID and/or combo?
|
||||
public override void OnModifiedInInventorySlot(IWorldAccessor world, ItemSlot slot, ItemStack extractedStack = null)
|
||||
{
|
||||
//Set keyid,combo if unset...
|
||||
if (this.LockStyle == LockKinds.Combination) {
|
||||
|
||||
if (this.CombinationCode == null)
|
||||
{
|
||||
GenerateCombination(slot, this);
|
||||
}
|
||||
} else if (this.LockStyle == LockKinds.Key) {
|
||||
if (this.KeyID.HasValue == false) {
|
||||
GenerateKeyId(slot, this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void GetHeldItemInfo(ItemSlot inSlot, System.Text.StringBuilder dsc, IWorldAccessor world, bool withDebugInfo)
|
||||
{
|
||||
base.GetHeldItemInfo(inSlot, dsc, world, withDebugInfo);
|
||||
|
||||
if (LockStyle == LockKinds.Combination) {
|
||||
dsc.AppendFormat("\nCombination#:");
|
||||
|
||||
if (this.CombinationCode != null) {
|
||||
foreach (var digit in this.CombinationCode) {
|
||||
dsc.AppendFormat(" {0:D}\t", digit);
|
||||
}
|
||||
} else {
|
||||
dsc.AppendFormat("\nCombination ????");
|
||||
}
|
||||
}
|
||||
|
||||
if (LockStyle == LockKinds.Key) {
|
||||
|
||||
if (this.KeyID.HasValue) dsc.AppendFormat("\nKeyID#: {0}", this.KeyID);
|
||||
}
|
||||
|
||||
if (LockTier > 0) {
|
||||
dsc.AppendFormat("\nTier#: {0}", this.LockTier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stores AccessControlNode in Tree-Attributes.
|
||||
/// </summary>
|
||||
/// <remarks>AccessControlNode -> (which are strangely part of 'ItemStack'...)</remarks>
|
||||
/// <param name="acn">Control node settings.</param>
|
||||
protected TreeAttribute TreeFromAttributes(AccessControlNode acn)
|
||||
{
|
||||
//Copy Combo number, keyID, type, ect...
|
||||
switch (acn.LockStyle)
|
||||
{
|
||||
case LockKinds.Classic:
|
||||
//OwnerId?
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//itemstack.Collectible.Attributes["clothescategory"].AsString(null);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected void GenerateCombination(ItemSlot slot, GenericLock genericLock)
|
||||
{
|
||||
Random randNum = new Random( );
|
||||
byte[] comboArray = new byte[this.LockTier + MinimumComboDigits];
|
||||
|
||||
for (int index = 0; index < this.LockTier + MinimumComboDigits; index++)
|
||||
{
|
||||
comboArray[index] = ( byte )randNum.Next(0, 9); //Extra high tiers - non-base10 ?
|
||||
}
|
||||
|
||||
slot.Itemstack.Attributes.SetBytes(_comboKey, comboArray);
|
||||
}
|
||||
|
||||
protected void GenerateKeyId(ItemSlot slot, GenericLock genericLock)
|
||||
{
|
||||
slot.Itemstack.Attributes.SetInt(AccessControlsMod._KeyIDKey, this.AccessControlsMod.NextKeyID);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
48
AccessControls/items/ItemCombolock.cs
Normal file
48
AccessControls/items/ItemCombolock.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using Vintagestory.API.Client;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Config;
|
||||
using Vintagestory.GameContent;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public class ItemCombolock : GenericLock
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
public override void OnHeldInteractStart(ItemSlot slot, EntityAgent byEntity, BlockSelection blockSel, EntitySelection entitySel, bool firstEvent, ref EnumHandHandling handling)
|
||||
{
|
||||
if (byEntity.World.Side == EnumAppSide.Client)
|
||||
{
|
||||
ClientAPI = (byEntity.World.Api as ICoreClientAPI);
|
||||
}
|
||||
|
||||
if (blockSel != null && byEntity.World.BlockAccessor.GetBlock(blockSel.Position).HasBehavior<BlockBehaviorLockable>( ))
|
||||
{
|
||||
IPlayer player = (byEntity as EntityPlayer).Player;
|
||||
|
||||
|
||||
|
||||
|
||||
if (AccessControlsMod.LockedForPlayer(blockSel.Position, player, this.Code) == false)//already has a lock...
|
||||
{
|
||||
ClientAPI?.TriggerIngameError(this, "cannotlock", Lang.Get("ingameerror-cannotlock"));
|
||||
} else {
|
||||
ClientAPI?.ShowChatMessage(Lang.Get("lockapplied"));
|
||||
slot.TakeOut(1);
|
||||
slot.MarkDirty( );
|
||||
|
||||
AccessControlsMod.ApplyLock(blockSel, player, slot);
|
||||
}
|
||||
|
||||
handling = EnumHandHandling.PreventDefault;
|
||||
return;
|
||||
}
|
||||
|
||||
base.OnHeldInteractStart(slot, byEntity, blockSel, entitySel, firstEvent, ref handling);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
FirstMachineAge_Common/Common.csproj
Normal file
52
FirstMachineAge_Common/Common.csproj
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{DE0A4E7D-E5FA-441D-A11A-8279E6AC5BBC}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>FirstMachineAge</RootNamespace>
|
||||
<AssemblyName>FirstMachineAge_Common</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="VintagestoryAPI">
|
||||
<HintPath>vs_libs\VintagestoryAPI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="VSCreativeMod">
|
||||
<HintPath>vs_libs\VSCreativeMod.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="VSEssentials">
|
||||
<HintPath>vs_libs\VSEssentials.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="VSSurvivalMod">
|
||||
<HintPath>vs_libs\VSSurvivalMod.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Helpers.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="vs_libs\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
144
FirstMachineAge_Common/Helpers.cs
Normal file
144
FirstMachineAge_Common/Helpers.cs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Vintagestory.API.Client;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.MathTools;
|
||||
|
||||
namespace FirstMachineAge
|
||||
{
|
||||
public static class Helpers
|
||||
{
|
||||
|
||||
|
||||
|
||||
public static string PrettyCoords(this BlockPos location, ICoreClientAPI ClientApi)
|
||||
{
|
||||
var start = ClientApi.World.DefaultSpawnPosition.AsBlockPos;
|
||||
|
||||
return string.Format("X{0}, Y{1}, Z{2}", location.X - start.X, location.Y, location.Z - start.Z);
|
||||
}
|
||||
|
||||
public static BlockPos AverageHighestPos(List<BlockPos> positions)
|
||||
{
|
||||
int x = 0, y = 0, z = 0, length = positions.Count;
|
||||
foreach (BlockPos pos in positions) {
|
||||
x += pos.X;
|
||||
y = Math.Max(y, pos.Y);//Mutant Y-axis, take "HIGHEST"
|
||||
z += pos.Z;
|
||||
}
|
||||
return new BlockPos(x / length, y, z / length);
|
||||
}
|
||||
|
||||
public static BlockPos PickRepresentativePosition(List<BlockPos> positions)
|
||||
{
|
||||
var averagePos = AverageHighestPos(positions);
|
||||
if (positions.Any(pos => pos.X == averagePos.X && pos.Y == averagePos.Y && pos.Z == averagePos.Z)) {
|
||||
return averagePos;//lucky ~ center was it!
|
||||
}
|
||||
|
||||
//Otherwise...pick one
|
||||
var whichever = positions.Last(poz => poz.Y == averagePos.Y);
|
||||
|
||||
return whichever;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Find a BLOCK partial path match: BlockID
|
||||
/// </summary>
|
||||
/// <returns>Matching finds</returns>
|
||||
/// <param name="assetName">Asset name.</param>
|
||||
public static Dictionary<int, string> ArbitrarytBlockIdHunter(this ICoreAPI CoreApi, AssetLocation assetName, EnumBlockMaterial? material = null)
|
||||
{
|
||||
Dictionary<int, string> arbBlockIDTable = new Dictionary<int, string>( );
|
||||
uint emptyCount = 0;
|
||||
|
||||
if (CoreApi.World.Blocks != null) {
|
||||
|
||||
#if DEBUG
|
||||
CoreApi.World.Logger.VerboseDebug(" World Blocks [Count: {0}]", CoreApi.World.Blocks.Count);
|
||||
#endif
|
||||
//If Brute force won't work; use GROOT FORCE!
|
||||
//var theBlock = ClientApi.World.BlockAccessor.GetBlock(0);
|
||||
|
||||
if (!material.HasValue) {
|
||||
foreach (Block blk in CoreApi.World.Blocks) {
|
||||
if (blk.IsMissing || blk.Id == 0 || blk.BlockId == 0) {
|
||||
emptyCount++;
|
||||
} else if (blk.Code != null && blk.Code.BeginsWith(assetName.Domain, assetName.Path)) {
|
||||
#if DEBUG
|
||||
//CoreApi.World.Logger.VerboseDebug("Block: [{0} ({1})] = #{2}", blk.Code.Path, blk.BlockMaterial, blk.BlockId);
|
||||
#endif
|
||||
|
||||
arbBlockIDTable.Add(blk.BlockId, blk.Code.Path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach (Block blk in CoreApi.World.Blocks) {
|
||||
if (blk.IsMissing || blk.Id == 0 || blk.BlockId == 0) {
|
||||
emptyCount++;
|
||||
} else if (blk.Code != null && material.Value == blk.BlockMaterial && blk.Code.BeginsWith(assetName.Domain, assetName.Path)) {
|
||||
#if DEBUG
|
||||
//CoreApi.World.Logger.VerboseDebug("Block: [{0} ({1})] = #{2}", blk.Code.Path, blk.BlockMaterial, blk.BlockId);
|
||||
#endif
|
||||
|
||||
arbBlockIDTable.Add(blk.BlockId, blk.Code.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
CoreApi.World.Logger.VerboseDebug("Block gaps: {0}", emptyCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
return arbBlockIDTable;
|
||||
}
|
||||
|
||||
public static long ToChunkIndex3D(this IBlockAccessor blocks, BlockPos blockPos)
|
||||
{
|
||||
return ToChunkIndex3D(blocks, blockPos.X / blocks.ChunkSize, blockPos.Y / blocks.ChunkSize, blockPos.Z / blocks.ChunkSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static long ToChunkIndex3D(this IBlockAccessor blocks, int chunkX, int chunkY, int chunkZ)
|
||||
{
|
||||
int ChunkMapSizeX = blocks.MapSizeX / blocks.ChunkSize;
|
||||
int ChunkMapSizeZ = blocks.MapSizeZ / blocks.ChunkSize;
|
||||
|
||||
return (( long )chunkY * ChunkMapSizeZ + chunkZ) * ChunkMapSizeX + chunkX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Chunk local index. Not block position!
|
||||
/// </summary>
|
||||
/// <remarks>Clamps to 5 bit ranges automagically</remarks>
|
||||
public static int ChunkBlockIndicie16(int X_index, int Y_index, int Z_index)
|
||||
{
|
||||
return ((Y_index & 31) * 32 + (Z_index & 31)) * 32 + (X_index & 31);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chunk index converted from block position (in world)
|
||||
/// </summary>
|
||||
/// <returns>The block indicie.</returns>
|
||||
/// <param name="blockPos">Block position.</param>
|
||||
/// <remarks>Clamps to 5 bit ranges automagically</remarks>
|
||||
public static int ChunkBlockIndicie16(BlockPos blockPos)
|
||||
{
|
||||
//Chunk masked
|
||||
return ((blockPos.Y & 31) * 32 + (blockPos.Z & 31)) * 32 + (blockPos.X & 31);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
FirstMachineAge_Common/Properties/AssemblyInfo.cs
Normal file
27
FirstMachineAge_Common/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("FirstMachineAge_Common")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("Melchior")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
|
||||
168
First_Machine_Age.sln
Normal file
168
First_Machine_Age.sln
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "FirstMachineAge_Common\Common.csproj", "{DE0A4E7D-E5FA-441D-A11A-8279E6AC5BBC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AccessControls", "AccessControls\AccessControls.csproj", "{180853A2-7E1D-4876-9D1E-AA8608D701C3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DE0A4E7D-E5FA-441D-A11A-8279E6AC5BBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DE0A4E7D-E5FA-441D-A11A-8279E6AC5BBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DE0A4E7D-E5FA-441D-A11A-8279E6AC5BBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DE0A4E7D-E5FA-441D-A11A-8279E6AC5BBC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{180853A2-7E1D-4876-9D1E-AA8608D701C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{180853A2-7E1D-4876-9D1E-AA8608D701C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{180853A2-7E1D-4876-9D1E-AA8608D701C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{180853A2-7E1D-4876-9D1E-AA8608D701C3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
Policies = $0
|
||||
$0.DotNetNamingPolicy = $1
|
||||
$1.DirectoryNamespaceAssociation = None
|
||||
$1.ResourceNamePolicy = FileFormatDefault
|
||||
$0.TextStylePolicy = $2
|
||||
$2.FileWidth = 120
|
||||
$2.TabsToSpaces = False
|
||||
$2.inheritsSet = VisualStudio
|
||||
$2.inheritsScope = text/plain
|
||||
$2.scope = text/plain
|
||||
$0.StandardHeader = $3
|
||||
$3.Text =
|
||||
$3.IncludeInNewFiles = True
|
||||
$0.NameConventionPolicy = $4
|
||||
$4.Rules = $5
|
||||
$5.NamingRule = $6
|
||||
$6.Name = Type Parameters
|
||||
$6.AffectedEntity = TypeParameter
|
||||
$6.VisibilityMask = VisibilityMask
|
||||
$6.NamingStyle = PascalCase
|
||||
$6.IncludeInstanceMembers = True
|
||||
$6.IncludeStaticEntities = True
|
||||
$6.RequiredPrefixes = $28
|
||||
$28.String = T
|
||||
$6.RequiredSuffixes = $29
|
||||
$29.String = Exception
|
||||
$5.NamingRule = $7
|
||||
$7.Name = Types
|
||||
$7.AffectedEntity = Class, Struct, Enum, Delegate
|
||||
$7.VisibilityMask = Public
|
||||
$7.NamingStyle = PascalCase
|
||||
$7.IncludeInstanceMembers = True
|
||||
$7.IncludeStaticEntities = True
|
||||
$5.NamingRule = $8
|
||||
$8.Name = Interfaces
|
||||
$8.RequiredPrefixes = $9
|
||||
$9.String = I
|
||||
$8.AffectedEntity = Interface
|
||||
$8.VisibilityMask = Public
|
||||
$8.NamingStyle = PascalCase
|
||||
$8.IncludeInstanceMembers = True
|
||||
$8.IncludeStaticEntities = True
|
||||
$5.NamingRule = $10
|
||||
$10.Name = Attributes
|
||||
$10.RequiredSuffixes = $11
|
||||
$11.String = Attribute
|
||||
$10.AffectedEntity = CustomAttributes
|
||||
$10.VisibilityMask = Public
|
||||
$10.NamingStyle = PascalCase
|
||||
$10.IncludeInstanceMembers = True
|
||||
$10.IncludeStaticEntities = True
|
||||
$5.NamingRule = $12
|
||||
$12.Name = Event Arguments
|
||||
$12.RequiredSuffixes = $13
|
||||
$13.String = EventArgs
|
||||
$12.AffectedEntity = CustomEventArgs
|
||||
$12.VisibilityMask = Public
|
||||
$12.NamingStyle = PascalCase
|
||||
$12.IncludeInstanceMembers = True
|
||||
$12.IncludeStaticEntities = True
|
||||
$5.NamingRule = $14
|
||||
$14.Name = Exceptions
|
||||
$14.RequiredSuffixes = $15
|
||||
$15.String = Exception
|
||||
$14.AffectedEntity = CustomExceptions
|
||||
$14.VisibilityMask = VisibilityMask
|
||||
$14.NamingStyle = PascalCase
|
||||
$14.IncludeInstanceMembers = True
|
||||
$14.IncludeStaticEntities = True
|
||||
$5.NamingRule = $16
|
||||
$16.Name = Methods
|
||||
$16.AffectedEntity = Methods
|
||||
$16.VisibilityMask = Protected, Public
|
||||
$16.NamingStyle = PascalCase
|
||||
$16.IncludeInstanceMembers = True
|
||||
$16.IncludeStaticEntities = True
|
||||
$5.NamingRule = $17
|
||||
$17.Name = Static Readonly Fields
|
||||
$17.AffectedEntity = ReadonlyField
|
||||
$17.VisibilityMask = Protected, Public
|
||||
$17.NamingStyle = PascalCase
|
||||
$17.IncludeInstanceMembers = False
|
||||
$17.IncludeStaticEntities = True
|
||||
$5.NamingRule = $18
|
||||
$18.Name = Fields
|
||||
$18.AffectedEntity = Field
|
||||
$18.VisibilityMask = Protected, Public
|
||||
$18.NamingStyle = PascalCase
|
||||
$18.IncludeInstanceMembers = True
|
||||
$18.IncludeStaticEntities = True
|
||||
$5.NamingRule = $19
|
||||
$19.Name = ReadOnly Fields
|
||||
$19.AffectedEntity = ReadonlyField
|
||||
$19.VisibilityMask = Protected, Public
|
||||
$19.NamingStyle = PascalCase
|
||||
$19.IncludeInstanceMembers = True
|
||||
$19.IncludeStaticEntities = False
|
||||
$5.NamingRule = $20
|
||||
$20.Name = Constant Fields
|
||||
$20.AffectedEntity = ConstantField
|
||||
$20.VisibilityMask = Protected, Public
|
||||
$20.NamingStyle = PascalCase
|
||||
$20.IncludeInstanceMembers = True
|
||||
$20.IncludeStaticEntities = True
|
||||
$5.NamingRule = $21
|
||||
$21.Name = Properties
|
||||
$21.AffectedEntity = Property
|
||||
$21.VisibilityMask = Protected, Public
|
||||
$21.NamingStyle = PascalCase
|
||||
$21.IncludeInstanceMembers = True
|
||||
$21.IncludeStaticEntities = True
|
||||
$5.NamingRule = $22
|
||||
$22.Name = Events
|
||||
$22.AffectedEntity = Event
|
||||
$22.VisibilityMask = Protected, Public
|
||||
$22.NamingStyle = PascalCase
|
||||
$22.IncludeInstanceMembers = True
|
||||
$22.IncludeStaticEntities = True
|
||||
$5.NamingRule = $23
|
||||
$23.Name = Enum Members
|
||||
$23.AffectedEntity = EnumMember
|
||||
$23.VisibilityMask = VisibilityMask
|
||||
$23.NamingStyle = PascalCase
|
||||
$23.IncludeInstanceMembers = True
|
||||
$23.IncludeStaticEntities = True
|
||||
$5.NamingRule = $24
|
||||
$24.Name = Parameters
|
||||
$24.AffectedEntity = Parameter
|
||||
$24.VisibilityMask = VisibilityMask
|
||||
$24.NamingStyle = CamelCase
|
||||
$24.IncludeInstanceMembers = True
|
||||
$24.IncludeStaticEntities = True
|
||||
$5.NamingRule = $25
|
||||
$25.Name = Type Parameters
|
||||
$25.RequiredPrefixes = $26
|
||||
$26.String = T
|
||||
$25.AffectedEntity = TypeParameter
|
||||
$25.VisibilityMask = VisibilityMask
|
||||
$25.NamingStyle = PascalCase
|
||||
$25.IncludeInstanceMembers = True
|
||||
$25.IncludeStaticEntities = True
|
||||
$0.VersionControlPolicy = $27
|
||||
$27.inheritsSet = Mono
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Loading…
Add table
Add a link
Reference in a new issue