• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javaandroidc++linuxc#objective-ccocoa誰得qtrubypythongamewindowsbathyscaphephpguic翻訳omegattwitterframeworktestbtronarduinovb.net計画中(planning stage)directxpreviewerゲームエンジンdom

First Machine Age's Mods (Combined repo.)


Commit MetaInfo

Revisãod737cf9311b430b0afcc4f0fa51599cc034ba0cd (tree)
Hora2019-11-18 08:28:10
Autormelchior <melchior@user...>
Commitermelchior

Mensagem de Log

W.I.P. #7b - workaround for duplicate events, placeholder states

Mudança Sumário

Diff

--- a/AccessControls/AccessControlMod.cs
+++ b/AccessControls/AccessControlMod.cs
@@ -51,6 +51,8 @@ namespace FirstMachineAge
5151 {
5252 this.ClientAPI = api;
5353
54+ //Called too early?
55+
5456 InitializeClientSide( );
5557 }
5658
@@ -134,14 +136,15 @@ namespace FirstMachineAge
134136
135137 public LockStatus LockState(BlockPos pos, IPlayer forPlayer)
136138 {
139+ pos = pos.Copy( );
137140 if (CoreAPI.Side.IsClient( )) {
138- if (Client_LockLookup.ContainsKey(pos.Copy( )))
141+ if (Client_LockLookup.ContainsKey(pos))
139142 {
140- return Client_LockLookup[pos.Copy( )].LockState;
143+ return Client_LockLookup[pos].LockState;
141144 }
142145 else
143146 {
144- return LockStatus.None;
147+ return LockStatus.Unknown;//Any lock state lookup is from a Behavior Lockable - thus should have _SOME_ entry
145148 }
146149 }
147150 else {
@@ -167,7 +170,7 @@ namespace FirstMachineAge
167170 }
168171 }
169172
170- return LockStatus.None;
173+ return LockStatus.None;//No entry made here (new?)
171174 }
172175
173176 public uint LockTier(BlockPos pos, IPlayer forPlayer)
@@ -235,11 +238,12 @@ namespace FirstMachineAge
235238 }
236239
237240 var controlNode = RetrieveACN(position.Copy( ));
238-
239- if (controlNode.LockStyle != LockKinds.None) {
240- return EvaulateACN_Rule(forPlayer, controlNode);
241+
242+ if ( controlNode != null && controlNode.LockStyle != LockKinds.None)
243+ {
244+ return EvaulateACN_Rule(forPlayer, controlNode);
241245 }
242-
246+
243247 return false;
244248 }
245249
@@ -287,9 +291,73 @@ namespace FirstMachineAge
287291
288292 return false;//Probably not...
289293 }
290-
294+
295+ /// <summary>
296+ /// Adds a 'None' lock entry client-side only.
297+ /// </summary>
298+ /// <param name="pos">Position.</param>
299+ /// <param name="owner">Owner.</param>
300+ public void AddPlaceHolder_SelfCache(BlockPos pos)
301+ {
302+ pos = pos.Copy( );
303+
304+ if (this.Client_LockLookup.ContainsKey(pos)) {
305+ Mod.Logger.Error("Can't overwrite cached lock entry located: {0}", pos);
306+ }
307+ else {
308+ var placheHolderState = new LockCacheNode( );
309+
310+ placheHolderState.Tier = 0;
311+ placheHolderState.OwnerName = ClientAPI.World.Player.PlayerName;
312+ placheHolderState.LockState = LockStatus.None;//Default Unlocked
313+
314+
315+ this.Client_LockLookup.Add(pos, placheHolderState);
316+ Mod.Logger.Debug("Added cach entry located: {0}", pos);
317+ }
318+
319+ }
320+
321+ public void AddPlaceHolder_Server(BlockPos pos)
322+ {
323+ if (CoreAPI.Side.IsServer( ))
324+ {
291325
326+ BlockPos blockPos = pos.Copy( );
327+
328+ AdjustBlockPostionForMultiBlockStructure(ref blockPos);
329+
330+ Mod.Logger.VerboseDebug("Creating placehodler; @{0} ", blockPos);
331+
332+ AccessControlNode placeHolder = new AccessControlNode();
333+
334+ if (ACN_IsNew(blockPos))
335+ {
336+ AddACN_ToServerACNs(blockPos, placeHolder);
337+
338+ //Send message to player that object was locked with X type lock (and combo / key#)
339+ //Send out ACN update selective broadcast msg...
340+ UpdateBroadcast(null, blockPos, placeHolder);
341+ }
342+ else {
343+ Mod.Logger.Warning("Prevented duplicate placeholder @{0} ...", blockPos);
344+ }
345+ }
346+ }
292347
348+ public void RemovelaceHolder_SelfCache(BlockPos pos)
349+ {
350+ pos = pos.Copy( );
351+
352+ if (this.Client_LockLookup.ContainsKey(pos) == false) {
353+ Mod.Logger.Error("Non-existant remove cached entry located: {0}", pos);
354+ }
355+ else {
356+ this.Client_LockLookup.Remove(pos);
357+ Mod.Logger.Debug("Removed cach entry located: {0}", pos);
358+ }
359+
360+ }
293361
294362 public void ApplyLock(BlockSelection blockSel, IPlayer player, ItemSlot itemSlot, string desc = null)
295363 {
@@ -343,30 +411,52 @@ namespace FirstMachineAge
343411 //Mark slot dirty?
344412 }
345413
346- if (Server_ACN.ContainsKey(chunkPos) && commitACN)
414+ if (commitACN)
347415 {
348- Mod.Logger.Debug("Appending to ChunkACNodes at {0}", chunkPos);
349- Server_ACN[chunkPos].Entries.Add(blockPos, newLockACN);
350- Server_ACN[chunkPos].Altered = true;
351- }
352- else
353- {
354- Mod.Logger.Debug("Created ChunkACNodes for {0}", chunkPos);
355- Server_ACN.Add(chunkPos, new ChunkACNodes(chunkPos));
356- Server_ACN[chunkPos].Entries.Add(blockPos, newLockACN);
357- Server_ACN[chunkPos].Altered = true;
416+ AddACN_ToServerACNs(blockPos, newLockACN);
358417 }
359418
360419 //Send message to player that object was locked with X type lock (and combo / key#)
361420 //Send out ACN update selective broadcast msg...
362421 if (commitACN) UpdateBroadcast(serverPlayer, blockPos, newLockACN );
363-
364422 }
365423
366- public void RemoveLock(BlockSelection blockSel, IPlayer player)
424+ /// <summary>
425+ /// Destroy A.C.N. node at this Position. [Permanent!]
426+ /// </summary>
427+ /// <returns>The lock.</returns>
428+ /// <param name="blockPos">Block position.</param>
429+ public void DestroyLock(BlockPos blockPos)
367430 {
431+ //By a creative player or world edit - erase any lock entry here.
432+ if (CoreAPI.Side.IsServer( ))
433+ {
434+ blockPos = blockPos.Copy( );
435+ //Server continues
436+ Vec3i chunkPos = ServerAPI.World.BlockAccessor.ToChunkPos(blockPos);
437+
438+ Mod.Logger.VerboseDebug("Removing ACL entry @{0} ", blockPos);
439+
440+ AccessControlNode remLockACN = Server_ACN[chunkPos].Entries[blockPos];
441+ remLockACN.LockStyle = LockKinds.None;//Remove from other players ACN caches'
442+ remLockACN.Tier = 0;
368443
369- BlockPos blockPos = blockSel.Position.Copy( );
444+ //Send message to other players that A.C.N. no longer exists here.
445+ UpdateBroadcast(null, blockPos, remLockACN);
446+
447+ Server_ACN[chunkPos].Entries.Remove(blockPos);
448+ }
449+ }
450+
451+ /// <summary>
452+ /// Removes the lock. (set A.C.N. back to LockState.None)
453+ /// </summary>
454+ /// <returns>The lock.</returns>
455+ /// <param name="blockSel">Block sel.</param>
456+ /// <param name="player">Player.</param>
457+ public void RemoveLock(BlockPos blockPos, IPlayer player)
458+ {
459+ blockPos = blockPos.Copy( );
370460
371461 //Client path only updates local cache?
372462 if (CoreAPI.Side.IsClient( )) {
@@ -378,20 +468,22 @@ namespace FirstMachineAge
378468 IServerPlayer serverPlayer = player as IServerPlayer;
379469 Vec3i chunkPos = ServerAPI.World.BlockAccessor.ToChunkPos(blockPos);
380470
381- Mod.Logger.VerboseDebug("Remove ACL entry @{0} by {1}", blockSel.Position, player.PlayerName);
382-
383- AccessControlNode remLockACN = Server_ACN[chunkPos].Entries[blockPos];
471+ Mod.Logger.VerboseDebug("De-lockify ACL entry @{0} by {1}", blockPos, player.PlayerName);
472+
473+ if (Server_ACN[chunkPos].Entries.ContainsKey(blockPos)) {
474+ AccessControlNode remLockACN = Server_ACN[chunkPos].Entries[blockPos];
384475 remLockACN.LockStyle = LockKinds.None;//Remove from other players ACN caches'
476+ remLockACN.Tier = 0;
385477
386- Server_ACN[chunkPos].Entries.Remove(blockPos);
387-
388-
389- //Send message to player that object was locked with X type lock (and combo / key#)
390- //Send out ACN update selective broadcast msg...
478+ //Send message to players that object was unlocked by a player
391479 UpdateBroadcast(serverPlayer, blockPos, remLockACN);
392-
393-
480+ }
481+ else
482+ {
483+ Mod.Logger.Warning("Removing non-existant A.C.N.: @{0} by {1}", blockPos, player.PlayerName);
484+ }
394485
486+
395487 }
396488
397489
@@ -403,23 +495,26 @@ namespace FirstMachineAge
403495 /// <param name="byBlockPos">By block position.</param>
404496 public AccessControlNode RetrieveACN(BlockPos byBlockPos)
405497 {
406- var chunkPos= ServerAPI.World.BulkBlockAccessor.ToChunkPos(byBlockPos);
407- AccessControlNode node = new AccessControlNode( );
498+ var chunkPos = ServerAPI.World.BulkBlockAccessor.ToChunkPos(byBlockPos);
499+ AccessControlNode node = null;
408500
409501 if (this.Server_ACN.ContainsKey(chunkPos)) {
410502
503+ if (Server_ACN[chunkPos].Entries.TryGetValue(byBlockPos, out node))
504+ {
505+ return node;
506+ }
507+
508+ } else {
509+ //Un cached chunk;
510+ LoadACN_fromChunk(chunkPos);
411511
412512 if (Server_ACN[chunkPos].Entries.TryGetValue(byBlockPos, out node)) {
413- return node;
513+ return node;
414514 }
415-
416-
417- } else {
418-
419515 }
420516
421-
422- return node;
517+ return null;
423518 }
424519
425520 // byte[] GetServerModdata (string key);
--- a/AccessControls/AccessControls_Internals.cs
+++ b/AccessControls/AccessControls_Internals.cs
@@ -81,9 +81,9 @@ namespace FirstMachineAge
8181
8282 //Await lock-GUI events, send cache updates via NW channel...
8383 accessControl_ServerChannel = ServerAPI.Network.RegisterChannel(_channel_name);
84- accessControl_ServerChannel.RegisterMessageType<LockGUIMessage>( );
85- accessControl_ServerChannel.RegisterMessageType<LockStatusList>( );
86- accessControl_ServerChannel.SetMessageHandler<LockGUIMessage>(LockGUIMessageHandler);
84+ accessControl_ServerChannel = accessControl_ServerChannel.RegisterMessageType<LockGUIMessage>( );
85+ accessControl_ServerChannel = accessControl_ServerChannel.RegisterMessageType<LockStatusList>( );
86+ accessControl_ServerChannel = accessControl_ServerChannel.SetMessageHandler<LockGUIMessage>(LockGUIMessageHandler);
8787
8888 ServerAPI.Event.PlayerJoin += TrackPlayerJoins;
8989 ServerAPI.Event.PlayerLeave += TrackPlayerLeaves;
@@ -103,6 +103,7 @@ namespace FirstMachineAge
103103 ServerAPI.Event.DidBreakBlock += RemoveACN_byBlockBreakage;
104104
105105 Mod.Logger.StoryEvent("...a tumbler turns, and opens\t*click*");
106+ Mod.Logger.VerboseDebug("ACN done server-side Init");
106107 }
107108
108109 private void RegisterStuff(ICoreAPI api)
@@ -116,48 +117,89 @@ namespace FirstMachineAge
116117
117118 private void InitializeClientSide( )
118119 {
120+ if (ClientAPI.Network.DidReceiveChannelId(_channel_name)) Mod.Logger.VerboseDebug("Server side channel: \"{0}\" existant", _channel_name);
119121 accessControl_ClientChannel = ClientAPI.Network.RegisterChannel(_channel_name);
120- accessControl_ClientChannel.RegisterMessageType<LockStatusList>( );
122+ accessControl_ClientChannel = accessControl_ClientChannel.RegisterMessageType<LockGUIMessage>( );
123+ accessControl_ClientChannel = accessControl_ClientChannel.RegisterMessageType<LockStatusList>( );
121124
122- accessControl_ClientChannel.SetMessageHandler<LockStatusList>(RecieveACNUpdate);//RX: Cache update
125+ accessControl_ClientChannel = accessControl_ClientChannel.SetMessageHandler<LockStatusList>(RecieveACNUpdate);//RX: Cache update
126+
127+ Mod.Logger.Debug("{0} channel connected: {1}", accessControl_ClientChannel.ChannelName, accessControl_ClientChannel.Connected);
123128
124129 Client_LockLookup = new Dictionary<BlockPos, LockCacheNode>( );
130+ Mod.Logger.VerboseDebug("ACN done client-side Init");
131+ }
132+
133+ internal bool ACN_IsNew(BlockPos blockPos)
134+ {
135+ Vec3i chunkPos = ServerAPI.World.BlockAccessor.ToChunkPos(blockPos);
136+
137+ if (Server_ACN.ContainsKey(chunkPos ))
138+ {
139+ if (Server_ACN[chunkPos].Entries.ContainsKey(blockPos))
140+ {
141+ return false;
142+ }
143+ }
125144
145+ return true;
126146 }
127147
128148 internal void LoadACN_fromChunk(Vec3i chunkPos)
129149 {
130- //Retrieve and add to local cache
150+ //ATTEMPT to Retrieve and add to local cache...
131151 IServerChunk targetChunk;
132152 byte[ ] data = null;
133153 long chunkIndex = ServerAPI.World.BulkBlockAccessor.ToChunkIndex3D(chunkPos);
134-
154+
135155 if (!ServerAPI.WorldManager.AllLoadedChunks.TryGetValue(chunkIndex, out targetChunk)) {
136156 //An unloaded chunk huh...
137157 Mod.Logger.Debug("Un-loaded chunk hit! {0}", chunkPos);
138158
139159 targetChunk = ServerAPI.WorldManager.GetChunk(chunkPos.X, chunkPos.Y, chunkPos.Z);
140160 }
141-
142-
161+
162+ if (targetChunk != null)
163+ {
164+ data = targetChunk.GetServerModdata(_AccessControlNodesKey);
165+ }
143166
144167 if (data != null && data.Length > 0) {
168+
169+ ChunkACNodes existingNodes = SerializerUtil.Deserialize<ChunkACNodes>(data);
170+
145171 #if DEBUG
146- Mod.Logger.VerboseDebug("Data for ACNs present in chunk: {0}", chunkPos);
172+ Mod.Logger.VerboseDebug("ACNs present in chunk: {0} - Nodes# {1}", chunkPos,existingNodes.Entries.Count);
147173 #endif
148174
149- ChunkACNodes acNodes = SerializerUtil.Deserialize<ChunkACNodes>(data);
150-
151- Server_ACN.Add(chunkPos.Clone( ), acNodes);
152- }
153- else if (targetChunk != null){
175+ Server_ACN.Add(chunkPos.Clone( ), existingNodes);
176+ } else {
154177 #if DEBUG
155- Mod.Logger.VerboseDebug("Absent ACN structures for chunk: {0} !", chunkPos);
178+ Mod.Logger.VerboseDebug("Absent ACN data for chunk: {0}! (placeholder added)", chunkPos);
156179 #endif
157180 //Setup new AC Node list for this chunk.
158- ChunkACNodes newAcNodes = new ChunkACNodes( );
181+ ChunkACNodes placeHolderNodes = new ChunkACNodes();
159182
160- Server_ACN.Add(chunkPos.Clone( ), newAcNodes);
183+ Server_ACN.Add(chunkPos.Clone( ), placeHolderNodes);
184+ }
185+
186+ }
187+
188+ internal void AddACN_ToServerACNs(BlockPos blockPos, AccessControlNode node )
189+ {
190+ Vec3i chunkPos = ServerAPI.World.BlockAccessor.ToChunkPos(blockPos);
191+
192+ if (Server_ACN.ContainsKey(chunkPos) ) {
193+ Mod.Logger.Debug("Appending to ChunkACNodes at {0}", chunkPos);
194+ Server_ACN[chunkPos].Entries.Add(blockPos, node);
195+ Server_ACN[chunkPos].Altered = true;
196+ }
197+ else {
198+ Mod.Logger.Debug("Created ChunkACNodes for {0}", chunkPos);
199+ Server_ACN.Add(chunkPos, new ChunkACNodes(chunkPos));
200+ Server_ACN[chunkPos].Entries.Add(blockPos, node);
201+ Server_ACN[chunkPos].Altered = true;
202+ Server_ACN[chunkPos].OriginChunk = chunkPos.Clone( );
161203 }
162204
163205 }
@@ -237,7 +279,7 @@ namespace FirstMachineAge
237279
238280 switch (theLock.LockStyle) {
239281 case LockKinds.None:
240- Mod.Logger.Error("Adding a non-lock to ClientCache, this is in error!");
282+ Mod.Logger.Error("Adding a non-lock to ClientCache, this is in error!");//Adding that is. Place-holders may exist like this
241283 break;
242284
243285 case LockKinds.Classic:
@@ -307,32 +349,28 @@ namespace FirstMachineAge
307349 private void RecieveACNUpdate(LockStatusList networkMessage)
308350 {
309351 //Client side; update local cache from whatever server sent
352+ if (networkMessage != null && networkMessage.LockStatesByBlockPos != null)
353+ {
354+ #if DEBUG
355+ Mod.Logger.VerboseDebug("Rx from Server; {0} LSL-nodes", networkMessage.LockStatesByBlockPos.Count);
356+ #endif
310357
311- if (networkMessage != null && networkMessage.LockStatesByBlockPos != null) {
312- #if DEBUG
313- Mod.Logger.VerboseDebug("ACN Rx from Server; {0} AC-nodes", networkMessage.LockStatesByBlockPos.Count);
314- #endif
315-
316- foreach (var update in networkMessage.LockStatesByBlockPos) {
317- if (Client_LockLookup.ContainsKey(update.Key)) {
318-
319- if (update.Value.LockState != LockStatus.None) {
320- //Replace
321- Client_LockLookup[update.Key.Copy( )] = update.Value;
322- }
323- else {
324- Client_LockLookup.Remove(update.Key.Copy( ));
325- }
326-
327- }
328- else {
329- //New
330- Client_LockLookup.Add(update.Key.Copy( ), update.Value);
358+ foreach (var update in networkMessage.LockStatesByBlockPos)
359+ {
360+ if (Client_LockLookup.ContainsKey(update.Key))
361+ {
362+ //Replace
363+ Client_LockLookup[update.Key.Copy( )] = update.Value;
364+ }
365+ else
366+ {
367+ //New
368+ Client_LockLookup.Add(update.Key.Copy( ), update.Value);
369+ }
370+ }
331371 }
332372
333373 }
334- }
335- }
336374
337375 private void SendClientACNUpdate(IServerPlayer toPlayer, BlockPos pos, AccessControlNode subjectACN)
338376 {
@@ -340,7 +378,7 @@ namespace FirstMachineAge
340378
341379 LockStatusList lsl = ComputeLSLFromACN(pos, subjectACN, toPlayer);
342380
343- accessControl_ServerChannel.SendPacket<LockStatusList>(lsl);
381+ accessControl_ServerChannel.SendPacket<LockStatusList>(lsl, toPlayer);
344382 }
345383
346384
@@ -350,10 +388,13 @@ namespace FirstMachineAge
350388 //TODO: side-Thread this ?
351389 ConnectedClient client = this.ServerMAIN.GetClientByUID(toPlayer.PlayerUID);
352390
353- if (client.IsPlayingClient) {
391+ if (client.State != EnumClientState.Offline) {
354392 //Pre-cooked 'cache' ACLs Computed for the current player in question
355393 LockStatusList lsl = ComputeLSLFromACNs(nodesList, toPlayer);
356394
395+ #if DEBUG
396+ Mod.Logger.VerboseDebug("Sending {0} LSL(s) for {1}", lsl.LockStatesByBlockPos.Count, toPlayer.PlayerName);
397+ #endif
357398 accessControl_ServerChannel.SendPacket<LockStatusList>(lsl, toPlayer);
358399 }
359400 }
@@ -388,18 +429,23 @@ namespace FirstMachineAge
388429
389430 private void AwakenPortunus(float delayed)
390431 {
391- //Start / Re-start thread to computed ACL node list to clients
392- #if DEBUG
432+
433+ if (ServerAPI.Server.CurrentRunPhase == EnumServerRunPhase.RunGame && ServerAPI.World.AllOnlinePlayers.Count( ) > 0)
434+ {
435+ //Start / Re-start thread to computed ACL node list to clients
436+ #if DEBUG
393437 Mod.Logger.VerboseDebug("Portunus re-trigger [{0}]", portunus_thread.ThreadState);
394- #endif
438+ #endif
395439
396- if (portunus_thread.ThreadState.HasFlag(ThreadState.Unstarted) ){
397- portunus_thread.Start( );
398- }
399- else if (portunus_thread.ThreadState.HasFlag(ThreadState.WaitSleepJoin)) {
400- //(re)Wake the sleeper!
401- portunus_thread.Interrupt( );
440+ if (portunus_thread.ThreadState.HasFlag(ThreadState.Unstarted)) {
441+ portunus_thread.Start( );
442+ }
443+ else if (portunus_thread.ThreadState.HasFlag(ThreadState.WaitSleepJoin)) {
444+ //(re)Wake the sleeper!
445+ portunus_thread.Interrupt( );
446+ }
402447 }
448+
403449 }
404450
405451 private void Portunus( )
@@ -407,7 +453,18 @@ namespace FirstMachineAge
407453 wake:
408454 Mod.Logger.VerboseDebug("Portunus thread awoken");
409455 try {
410- //For all online players - ACN's for *new* chunks entered/in
456+ //####################### Fetch ACN's for *INTRODUCED* (to A.C. system) Chunks... ######################
457+ foreach (var chunkEntry in ServerAPI.WorldManager.AllLoadedChunks) {
458+
459+ Vec3i loadedPos = ServerMAIN.WorldMap.ChunkPosFromChunkIndex3D(chunkEntry.Key);
460+
461+ if (Server_ACN.ContainsKey(loadedPos) == false)
462+ {
463+ LoadACN_fromChunk(loadedPos);
464+ }
465+ }
466+
467+ //####################### For all online players - ACN's for *new* chunks entered/in ###########################
411468 foreach (var player in ServerAPI.World.AllOnlinePlayers) {//TODO: Parallel.ForEach
412469
413470 //var client = this.ServerMAIN.GetConnectedClient(player.PlayerUID);
@@ -443,14 +500,9 @@ namespace FirstMachineAge
443500 }
444501 //Keys should already be marking their previous/current owner (called externally) - ACN
445502
446-
447-
448-
449- //var chunk_ACLs_Cached = this.previousChunkSet_byPlayerUID.
450-
451503 }
452504
453- //Persist & SAVE-COMMIT Altered ACNs !
505+ //########################### Persist & SAVE-COMMIT Altered ACNs ! #########################
454506 var alteredCount = Server_ACN.Count(ac => ac.Value.Altered == true);
455507 if (alteredCount > 0) Mod.Logger.Debug("There are {0} altered chunk Nodes to persist", alteredCount);
456508
@@ -524,14 +576,13 @@ namespace FirstMachineAge
524576
525577 private LockStatusList ComputeLSLFromACN(BlockPos blockPos , AccessControlNode updatedLock, IServerPlayer tgtPlayer)
526578 {
527-
528579 bool locked = EvaulateACN_Rule(tgtPlayer, updatedLock);
529580
530581 LockCacheNode lcn = new LockCacheNode( );
531582
532- switch (updatedLock.LockStyle) {
583+ switch (updatedLock.LockStyle) {
533584 case LockKinds.None:
534- lcn.LockState = LockStatus.None;//Only used for 'remove' orders...
585+ lcn.LockState = LockStatus.None;//Only used for lock 'removal'
535586 break;
536587
537588 case LockKinds.Classic:
--- a/AccessControls/behaviors/BlockBehaviorComplexLockable.cs
+++ b/AccessControls/behaviors/BlockBehaviorComplexLockable.cs
@@ -11,12 +11,13 @@ namespace FirstMachineAge
1111 {
1212
1313 /// <summary>
14- /// Multi-use Lockable behavior for combo/key/other locks
14+ /// Multi-use Lockable behavior for combo/key/fancy locks
1515 /// </summary>
1616 /// <remarks>Replaces the old behavior...</remarks>
1717 public class BlockBehaviorComplexLockable : BlockBehaviorLockable
1818 {
1919 private AccessControlsMod acm;
20+ private ILogger Logger;
2021
2122 public BlockBehaviorComplexLockable(Block block) : base(block)
2223 {
@@ -26,6 +27,7 @@ namespace FirstMachineAge
2627 public override void OnLoaded(ICoreAPI api)
2728 {
2829 acm = api.ModLoader.GetModSystem<AccessControlsMod>( );
30+ Logger = acm.Mod.Logger;
2931 }
3032
3133
@@ -38,40 +40,45 @@ namespace FirstMachineAge
3840 {
3941 LockStatus lockState = acm.LockState(blockPos, byPlayer);
4042
41- if (world.Side == EnumAppSide.Client)
42- {
43- ICoreClientAPI clientAPI = (world.Api as ICoreClientAPI);
43+ bool clientSide = world.Side.IsClient( );
44+ ICoreClientAPI clientAPI = clientSide ? (world.Api as ICoreClientAPI): null;
4445
4546 switch (lockState)
4647 {
48+ case LockStatus.None:
49+ handling = EnumHandling.PassThrough;
50+ return true;
51+
4752 case LockStatus.ComboUnknown:
4853 //Does Not already know combo...
49- ShowComboLockGUI(clientAPI, byPlayer,blockPos);
54+ if (clientSide) ShowComboLockGUI(clientAPI, byPlayer,blockPos);
5055
5156 break;
5257
5358 case LockStatus.KeyHave:
54- clientAPI.TriggerChatMessage("opened with a key...");
59+ if (clientSide) clientAPI.TriggerChatMessage("opened with a key...");
5560 handling = EnumHandling.PassThrough;
5661 return true;
5762
5863 case LockStatus.KeyNope:
5964 //Did not have key...
60- clientAPI.TriggerIngameError(this, "locked", Lang.Get("ingameerror-nokey", new object[0]));
65+ if (clientSide) clientAPI.TriggerIngameError(this, "locked", Lang.Get("ingameerror-nokey", new object[0]));
66+ break;
67+
68+ case LockStatus.Unknown:
69+ if (clientSide) clientAPI.TriggerIngameError(this, "error", "Access-Control malfunction or lag?!");
6170 break;
6271
6372 default:
6473 //Normal or 'default' lock:
65- clientAPI.TriggerIngameError(this, "locked", Lang.Get("ingameerror-locked", new object[0]));
74+ if (clientSide) clientAPI.TriggerIngameError(this, "locked", Lang.Get("ingameerror-locked", new object[0]));
6675 break;
6776 }
68- }
6977
7078 handling = EnumHandling.PreventSubsequent;
7179 return false;
7280 }
7381
74-
7582 return base.OnBlockInteractStart(world, byPlayer, blockSel, ref handling);
7683 }
7784
@@ -102,6 +109,55 @@ namespace FirstMachineAge
102109 return String.Empty;
103110 }
104111
112+
113+ public override void OnBlockPlaced(IWorldAccessor world, BlockPos blockPos, ref EnumHandling handling)
114+ {
115+ #if DEBUG
116+ Logger.VerboseDebug("BlockBehaviorComplexLockable::OnBlockPlaced()");
117+ #endif
118+
119+ if (world.Side.IsClient( )) {
120+ //OnBlockPlaced --> add entry to (client) cache!
121+ acm.AddPlaceHolder_SelfCache(blockPos);
122+ }
123+ else {
124+ //Placeholder for SERVER too!
125+ acm.AddPlaceHolder_Server(blockPos);
126+ }
127+
128+ base.OnBlockPlaced(world, blockPos, ref handling);
129+ }
130+
131+ public override void OnBlockRemoved(IWorldAccessor world, BlockPos pos, ref EnumHandling handling)
132+ {
133+ #if DEBUG
134+ Logger.VerboseDebug("BlockBehaviorComplexLockable::OnBlockRemoved()");
135+#endif
136+
137+ if (world.Side.IsClient( )) {
138+ acm.RemovelaceHolder_SelfCache(pos);
139+ } else
140+ {
141+ acm.DestroyLock(pos);
142+ }
143+
144+ base.OnBlockRemoved(world, pos, ref handling);
145+ }
146+
147+ public override void OnBlockBroken(IWorldAccessor world, BlockPos pos, IPlayer byPlayer, ref EnumHandling handling)
148+ {
149+
150+ if (world.Side.IsClient( )) {
151+ acm.RemovelaceHolder_SelfCache(pos);
152+ }
153+ else {
154+ acm.RemoveLock(pos, byPlayer);
155+ }
156+
157+ base.OnBlockBroken(world, pos, byPlayer, ref handling);
158+ }
159+
160+
105161 protected void ShowComboLockGUI(ICoreClientAPI clientAPI, IPlayer byPlayer, BlockPos blockPos)
106162 {
107163 //Popup GUI window;
--- a/AccessControls/data/AccessControlNode.cs
+++ b/AccessControls/data/AccessControlNode.cs
@@ -28,7 +28,7 @@ namespace FirstMachineAge
2828 {
2929 Entries = new Dictionary<BlockPos, AccessControlNode>( );
3030 Altered = true;
31- OriginChunk = originChunk;
31+ OriginChunk = originChunk.Clone();
3232 }
3333
3434 [ProtoMember(1)]
@@ -112,7 +112,9 @@ namespace FirstMachineAge
112112 [ProtoContract]
113113 public class LockStatusList
114114 {
115- private LockStatusList( ) { throw new NotSupportedException(); }
115+ private LockStatusList( ) {
116+ LockStatesByBlockPos = new Dictionary<BlockPos, LockCacheNode>( );
117+ }
116118
117119 public LockStatusList(BlockPos here)
118120 {
@@ -142,7 +144,7 @@ namespace FirstMachineAge
142144 public Dictionary<BlockPos,LockCacheNode> LockStatesByBlockPos;
143145
144146 /*
145- [ProtoMember(1)]
147+ [ProtoMember(2)]
146148 public Vec3i ChunkOrigin;
147149 */
148150
--- a/AccessControls/items/ItemCombolock.cs
+++ b/AccessControls/items/ItemCombolock.cs
@@ -12,7 +12,7 @@ namespace FirstMachineAge
1212
1313
1414
15-
15+ //TODO: Remove all this for generic?
1616 public override void OnHeldInteractStart(ItemSlot slot, EntityAgent byEntity, BlockSelection blockSel, EntitySelection entitySel, bool firstEvent, ref EnumHandHandling handling)
1717 {
1818 if (byEntity.World.Side.IsClient())
@@ -26,7 +26,7 @@ namespace FirstMachineAge
2626
2727
2828 if (AccessControlsMod.LockState(blockSel.Position, player) != LockStatus.None )//already has a lock...?
29- {
29+ {//TODO: Add Lock owner text
3030 ClientAPI?.TriggerIngameError(this, "cannotlock", Lang.Get("ingameerror-cannotlock"));
3131 } else {
3232