Browse Source

Add client-side terrain replacement when terrain add is rejected

tags/v0.0.3
NGnius (Graham) 3 years ago
parent
commit
476d6382da
14 changed files with 427 additions and 45 deletions
  1. +0
    -9
      CLre/API/App/ClientEngines.cs
  2. +0
    -3
      CLre/API/Characters/Character.cs
  3. +8
    -8
      CLre/API/Engines/FrontEndEngines.cs
  4. +4
    -4
      CLre/API/Engines/GameEngines.cs
  5. +5
    -4
      CLre/API/Synergy/ClientHandshakeEngine.cs
  6. +0
    -3
      CLre/API/Synergy/ClientMessagingEngine.cs
  7. +75
    -0
      CLre/API/Synergy/Tweaks/SerializedCLreTerrainModifyRejection.cs
  8. +7
    -0
      CLre/API/Utility/Reflection.cs
  9. +6
    -1
      CLre/CLre.cs
  10. +244
    -0
      CLre/Fixes/TerrainModifyReset.cs
  11. +23
    -4
      CLre_server/API/Synergy/Tweaks/SerializedCLreTerrainModifyRejection.cs
  12. +16
    -0
      CLre_server/API/Tools/AccessToolsWarnings.cs
  13. +4
    -1
      CLre_server/API/Utility/Reflection.cs
  14. +35
    -8
      CLre_server/Tweaks/TerrainModificationExclusionZone.cs

+ 0
- 9
CLre/API/App/ClientEngines.cs View File

@@ -14,9 +14,6 @@ namespace CLre.API.App
if (gameEngineReady != null) gameEngineReady(this, new GameReady { });
}

public override IEntitiesDB entitiesDB { get; set; }
public override IEntityFactory entityFactory { get; set; }
public void OnFrameworkInitialized()
{
// TODO framework init event
@@ -33,9 +30,6 @@ namespace CLre.API.App
{
}

public override IEntitiesDB entitiesDB { get; set; }
public override IEntityFactory entityFactory { get; set; }
public void OnFrameworkInitialized()
{
if (gameFrameworkReady != null) gameFrameworkReady(this, new GameReady { });
@@ -55,8 +49,5 @@ namespace CLre.API.App
{
if (menuEngineReady != null) menuEngineReady(this, new MenuReady { });
}

public override IEntitiesDB entitiesDB { get; set; }
public override IEntityFactory entityFactory { get; set; }
}
}

+ 0
- 3
CLre/API/Characters/Character.cs View File

@@ -54,9 +54,6 @@ namespace CLre.API.Characters
{
}

public override IEntitiesDB entitiesDB { get; set; }
public override IEntityFactory entityFactory { get; set; }

public bool GetGodModeRequested()
{
if (entitiesDB == null) return false;


+ 8
- 8
CLre/API/Engines/FrontEndEngines.cs View File

@@ -21,8 +21,8 @@ namespace CLre.API.Engines
}

public abstract void Ready();
public abstract IEntitiesDB entitiesDB { get; set; }
public abstract IEntityFactory entityFactory { get; set; }
public IEntitiesDB entitiesDB { get; set; }
public IEntityFactory entityFactory { get; set; }
}
/// <summary>
@@ -41,8 +41,8 @@ namespace CLre.API.Engines
}

public abstract void Ready();
public abstract IEntitiesDB entitiesDB { get; set; }
public abstract IEntityFactory entityFactory { get; set; }
public IEntitiesDB entitiesDB { get; set; }
public IEntityFactory entityFactory { get; set; }
}
/// <summary>
@@ -60,8 +60,8 @@ namespace CLre.API.Engines
}

public abstract void Ready();
public abstract IEntitiesDB entitiesDB { get; set; }
public abstract IEntityFactory entityFactory { get; set; }
public IEntitiesDB entitiesDB { get; set; }
public IEntityFactory entityFactory { get; set; }
}
/// <summary>
@@ -79,8 +79,8 @@ namespace CLre.API.Engines
}

public abstract void Ready();
public abstract IEntitiesDB entitiesDB { get; set; }
public abstract IEntityFactory entityFactory { get; set; }
public IEntitiesDB entitiesDB { get; set; }
public IEntityFactory entityFactory { get; set; }
}

[HarmonyPatch(typeof(FrontEnd.MainFrontEnd), "BuildEngines")]


+ 4
- 4
CLre/API/Engines/GameEngines.cs View File

@@ -12,8 +12,8 @@ namespace CLre.API.Engines
}
public abstract void Ready();
public abstract IEntitiesDB entitiesDB { get; set; }
public abstract IEntityFactory entityFactory { get; set; }
public IEntitiesDB entitiesDB { get; set; }
public IEntityFactory entityFactory { get; set; }
}
public abstract class GameObsoleteEnginePostBuild : ICLreEngine
@@ -24,8 +24,8 @@ namespace CLre.API.Engines
}
public abstract void Ready();
public abstract IEntitiesDB entitiesDB { get; set; }
public abstract IEntityFactory entityFactory { get; set; }
public IEntitiesDB entitiesDB { get; set; }
public IEntityFactory entityFactory { get; set; }
}

[HarmonyPatch(typeof(GameFramework.MainLevel), "BuildDeprecatedEngines")]


+ 5
- 4
CLre/API/Synergy/ClientHandshakeEngine.cs View File

@@ -3,6 +3,7 @@ using CLre.API.Engines;
using GameNetworkLayer.Shared;
using HarmonyLib;
using Svelto.ECS;
using VoxelFarm.GameServer;

namespace CLre.API.Synergy
{
@@ -40,9 +41,6 @@ namespace CLre.API.Synergy
Utility.Logging.MetaLog($"Received CLre handshake! {p}");
}

public override IEntitiesDB entitiesDB { get; set; }
public override IEntityFactory entityFactory { get; set; }

public IEnumerator Sender(SerializedCLreHandshake payload)
{
yield return null;
@@ -72,12 +70,15 @@ namespace CLre.API.Synergy
internal static object netMessageListener;

internal static object netMessageSender;

internal static TerrainModelClientServer tmcs;
[HarmonyPostfix]
public static void AfterMethodCall(object ____netMessageListener, object ____netMessageSender)
public static void AfterMethodCall(object ____netMessageListener, object ____netMessageSender, TerrainModelClientServer ____terrainModelServerPrediction)
{
netMessageListener = ____netMessageListener;
netMessageSender = ____netMessageSender;
tmcs = ____terrainModelServerPrediction;
}
}
}

+ 0
- 3
CLre/API/Synergy/ClientMessagingEngine.cs View File

@@ -54,9 +54,6 @@ namespace CLre.API.Synergy
});
}

public override IEntitiesDB entitiesDB { get; set; }
public override IEntityFactory entityFactory { get; set; }

public ClientMessagingEngine(): base()
{
App.Client.GameJoin += (_, __) => { MessageSender().Run(); };


+ 75
- 0
CLre/API/Synergy/Tweaks/SerializedCLreTerrainModifyRejection.cs View File

@@ -0,0 +1,75 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using Game.Handhelds;
using NetworkFramework.Shared;
using UnityEngine;

namespace CLre.API.Synergy.Tweaks
{
public struct SerializedCLreTerrainModifyRejection: ISerializedNetData
{
public RejectionFlag Flags;

public uint resourceId;

public Vector3 hit;

public string toolKey;

public ToolModeType toolMode;

public byte[] Serialize()
{
using (MemoryStream stream = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write((byte)Flags);
writer.Write(resourceId);
writer.Write(hit.x);
writer.Write(hit.y);
writer.Write(hit.z);
writer.Write(toolKey);
writer.Write((byte)toolMode);
return stream.ToArray();
}
}
}

public void Deserialize(byte[] data)
{
using (MemoryStream stream = new MemoryStream(data))
{
using (BinaryReader reader = new BinaryReader(stream))
{
Flags = (RejectionFlag)reader.ReadByte();
resourceId = reader.ReadUInt32();
float x = reader.ReadSingle();
float y = reader.ReadSingle();
float z = reader.ReadSingle();
hit = new Vector3(x, y, z);
toolKey = reader.ReadString();
toolMode = (ToolModeType)reader.ReadByte();
}
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Ok()
{
return (Flags & RejectionFlag.Rejection) == RejectionFlag.None;
}
}

[Flags]
public enum RejectionFlag : byte
{
None = 0,
Rejection = 1,
Proximity = 1 << 1,
Permission = 1 << 2,
AccountNotFound = 1 << 3,
InitError = 1 << 4,
}
}

+ 7
- 0
CLre/API/Utility/Reflection.cs View File

@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Game.DataLoader;
using GameNetworkLayer.Client;
using GameNetworkLayer.Shared;
using HarmonyLib;
using NetworkFramework.Shared;
using OpenCVForUnity;
using Svelto.DataStructures;
using Svelto.ECS;

@@ -34,6 +37,10 @@ namespace CLre.API.Utility
public delegate void INetMsgClientListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBClient<T> proc) where T: struct, ISerializedNetData;

public delegate void DeprecatedDispatcher_Dispatch<T>(ref T value);

public delegate Dictionary<string, BaseData> IDataDB_GetValues();
// useful reflection functions
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
{


+ 6
- 1
CLre/CLre.cs View File

@@ -51,6 +51,7 @@ namespace CLre
Fixes.InitLogSooner.Init();
Fixes.MiniScreenHelper.Init();
Fixes.UnderStructureCollider.Init();
Fixes.TerrainModifyReset.Init();
// API init
API.Synergy.ClientHandshakeEngine.Init();
@@ -106,7 +107,11 @@ namespace CLre

API.App.Client.MenuReady += (_, __) => { API.Utility.Logging.MetaLog("Menu engine ready event fired!"); };
API.App.Client.GameReady += (_, __) => { API.Utility.Logging.MetaLog("Game engine ready event fired!"); };
API.App.Client.GameFrameworkReady += (_, __) => { API.Utility.Logging.MetaLog("Game framework ready event fired!"); };
API.App.Client.GameFrameworkReady += (_, __) =>
{
API.Utility.Logging.MetaLog("Game framework ready event fired!");
API.Utility.Logging.MetaLog($"PhotonChat Connection Protocol: {PhotonChatUI.Chat.Instance.ConnectionProtocol}");
};
API.App.Client.GameFrameworkExit += (_, __) => { API.Utility.Logging.MetaLog("Game framework exit event fired!"); };
Character c = Character.Local();


+ 244
- 0
CLre/Fixes/TerrainModifyReset.cs View File

@@ -0,0 +1,244 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using CLre.API.Synergy;
using CLre.API.Utility;
using Game.DataLoader;
using Game.Handhelds;
using GameNetworkLayer.Shared;
using HarmonyLib;
using NetworkFramework.Shared;
using Svelto.ECS;
using UnityEngine;
using VoxelFarm.GameServer;

namespace CLre.Fixes
{
[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.Initialiser, id = 8)]
public class TerrainModifyReset
{
private static TerrainModifyResetEngine _tmrEngine = null;
public static void Init()
{
_tmrEngine = new TerrainModifyResetEngine();
}
}

[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.Workaround, id = 8)]
public class TerrainModifyResetEngine : API.Engines.GameObsoleteEnginePostBuild, IDataAccess
{
private Reflection.INetMsgClientListener_RegisterListener<API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection> _registerListener;

public override void Ready()
{
_registerListener =
Reflection.MethodAsDelegate<Reflection.INetMsgClientListener_RegisterListener<API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection>>(
"GameNetworkLayer.Client.NetMessageClientListener:RegisterListener",
generics: new [] {typeof(API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection)},
instance: MainLevel_BuildClasses_Patch.netMessageListener);
_registerListener(NetworkDispatcherCode.TerrainModificationFailed, OnMessageReceived);
}
private void OnMessageReceived(ref API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection data)
{
if (!data.Ok())
{
// reset terrain visuals
// TODO optimise
#if DEBUG
API.Utility.Logging.MetaLog($"data.resourceId: {data.resourceId}");
#endif
AddTerrain(ref data);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void GetTerrainRelativePosition(ref Vector3 pos)
{
// This uses decompiled code from VoxelFarm.Shared.VoxelFarmGameUtils:GetTerrainRelativePosition
// there's no point in calling that simple function when I have to jump through hoops with reflection
//
// there's also nothing particularly unique (ie copyrightable) about this code,
// so the lawyers can suck it (also suing a benevolent project is a shitty move)
pos.x /= 0.083333336f;
pos.y /= 0.041666668f;
pos.z /= 0.083333336f;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AddTerrain(ref API.Synergy.Tweaks.SerializedCLreTerrainModifyRejection data)
{
// This uses decompiled code from VoxelFarm.GameServer.TerrainModelClientServer:AddTerrain
// there's no point in calling that simple function when I have to jump through hoops with reflection
// to supply the parameters to it
//
// Also this is not unique functionality, and comes from the logic of how the placement modes work
switch (data.toolMode)
{
case ToolModeType.Block:
MainLevel_BuildClasses_Patch.tmcs.AddDisc(0, data.hit, (int)data.resourceId, 5, 5);
break;
case ToolModeType.Disc:
MainLevel_BuildClasses_Patch.tmcs.AddDisc(0, data.hit, (int)data.resourceId, 1, 5);
break;
case ToolModeType.Voxel:
MainLevel_BuildClasses_Patch.tmcs.AddSingleVoxel(0, data.hit, (int)data.resourceId);
break;
}
}

public IDataDB dataDB { get; set; }
}
[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.HarmonyPatch, id = 8)]
[HarmonyPatch]
class TerrainPendingModificationEngineClient_Add_Patch
{
internal static object _terrainModifyInputNode = null;

[HarmonyPrefix]
public static void BeforeMethodCall(object node)
{
#if DEBUG
API.Utility.Logging.MetaLog("Intercepting VoxelFarm.Client.TerrainPendingModificationEngineClient:Add()");
#endif
_terrainModifyInputNode = node;
}
[HarmonyTargetMethod]
public static MethodBase Target()
{
return AccessTools.Method("VoxelFarm.Client.TerrainPendingModificationEngineClient:Add", new []{ AccessTools.TypeByName("VoxelFarm.Shared.TerrainModifyInputNode")});
}
}
/*[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.HarmonyPatch, id = 8)]
[HarmonyPatch]
class TerrainPendingModificationEngineClient_OnBlockRemoved_Patch
{
[HarmonyPrefix]
public static bool BeforeMethodCall(int sender, ref ISerializedNetData terrainModifyInputData)
{
#if DEBUG
API.Utility.Logging.MetaLog($"Intercepting VoxelFarm.Client.TerrainPendingModificationEngineClient:OnBlockRemoved({sender}, {terrainModifyInputData})");
#endif
return false;
}
[HarmonyTargetMethod]
public static MethodBase Target()
{
return AccessTools.Method("VoxelFarm.Client.TerrainPendingModificationEngineClient:OnBlockRemoved");
}
}*/
[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.Debug, id = 8)]
[HarmonyPatch]
class SpadeEngine_FinishDigging_Patch
{
internal static int CurrentMaterialId = 0;
[HarmonyPrefix]
public static void BeforeMethodCall(object toolNode, int ____currentMaterialId)
{
#if DEBUG
API.Utility.Logging.MetaLog($"Intercepting Game.Handhelds.SpadeEngine:FinishDigging:GetTerrainMaterial(...) material:{____currentMaterialId}");
#endif
CurrentMaterialId = ____currentMaterialId;
}
[HarmonyTargetMethod]
public static MethodBase Target()
{
return AccessTools.Method("Game.Handhelds.SpadeEngine:FinishDigging");
}
}
[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.Debug, id = 8)]
[HarmonyPatch]
class TerrainModifyInputData_InjectValues_Patch
{
[HarmonyPrefix]
public static void BeforeMethodCall(ref uint resourceId)
{
#if DEBUG
API.Utility.Logging.MetaLog($"VoxelFarm.Shared.TerrainModifyInputData:InjectValues({resourceId}, ...)");
#endif
if (resourceId == 0) resourceId = (uint) SpadeEngine_FinishDigging_Patch.CurrentMaterialId;
}
[HarmonyTargetMethod]
public static MethodBase Target()
{
return AccessTools.Method("VoxelFarm.Shared.TerrainModifyInputData:InjectValues");
}
}
[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.HarmonyPatch, id = 8)]
[HarmonyPatch]
class NetMessageClientListener_RegisterListener_Patch
{
[HarmonyPrefix]
public static bool BeforeMethodCall(NetworkDispatcherCode code)
{
#if DEBUG
API.Utility.Logging.MetaLog($"Intercepting GameNetworkLayer.Client.NetMessageClientListener:RegisterListener({code}, ...)");
#endif
// don't allow for standard TerrainModificationFailed listener to be registered
// because it's a different type and that's illegal
return code != NetworkDispatcherCode.TerrainModificationFailed;
}
[HarmonyTargetMethod]
public static MethodBase Target()
{
return AccessTools.Method("GameNetworkLayer.Client.NetMessageClientListener:RegisterListener", generics: new []{ typeof(SerializedEmptyNetData)});
}
}

// this disables terrain destruction
/*[Bugfix(name = "TerrainModificationFailedHandler",
description = "Actually handle TerrainModificationFailed network messages",
more = "https://trello.com/c/Pq5lcB1p/23-moderation-tools",
component = BugfixType.Debug, id = 8)]
[HarmonyPatch]
class TerrainModificationEngineServer_RemoveTerrainInput_Patch
{
[HarmonyPrefix]
public static bool BeforeMethodCall(int senderPlayerId, ref ISerializedNetData data)
{
#if DEBUG
API.Utility.Logging.MetaLog($"Intercepting client-side GameServer.VoxelFarm.Server.TerrainModificationEngineServer:RemoveTerrainInput({senderPlayerId}, {data})");
#endif
return false;
}
[HarmonyTargetMethod]
public static MethodBase Target()
{
return AccessTools.Method("GameServer.VoxelFarm.Server.TerrainModificationEngineServer:RemoveTerrainInput");
}
}*/
}

+ 23
- 4
CLre_server/API/Synergy/Tweaks/SerializedCLreTerrainModifyRejection.cs View File

@@ -1,7 +1,9 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using Game.Handhelds;
using NetworkFramework.Shared;
using UnityEngine;

namespace CLre_server.API.Synergy.Tweaks
{
@@ -9,8 +11,14 @@ namespace CLre_server.API.Synergy.Tweaks
{
public RejectionFlag Flags;

public uint Cell;
public uint resourceId;

public Vector3 hit;

public string toolKey;

public ToolModeType toolMode;

public byte[] Serialize()
{
using (MemoryStream stream = new MemoryStream())
@@ -18,7 +26,12 @@ namespace CLre_server.API.Synergy.Tweaks
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write((byte)Flags);
writer.Write(Cell);
writer.Write(resourceId);
writer.Write(hit.x);
writer.Write(hit.y);
writer.Write(hit.z);
writer.Write(toolKey);
writer.Write((byte)toolMode);
return stream.ToArray();
}
}
@@ -31,7 +44,13 @@ namespace CLre_server.API.Synergy.Tweaks
using (BinaryReader reader = new BinaryReader(stream))
{
Flags = (RejectionFlag)reader.ReadByte();
Cell = reader.ReadUInt32();
resourceId = reader.ReadUInt32();
float x = reader.ReadSingle();
float y = reader.ReadSingle();
float z = reader.ReadSingle();
hit = new Vector3(x, y, z);
toolKey = reader.ReadString();
toolMode = (ToolModeType)reader.ReadByte();
}
}
}


+ 16
- 0
CLre_server/API/Tools/AccessToolsWarnings.cs View File

@@ -51,5 +51,21 @@ namespace CLre_server.API.Tools
}
}
}
[HarmonyPatch(typeof(AccessTools), "Method",
new Type[] {typeof(Type), typeof(string), typeof(Type[]), typeof(Type[])})]
class AccessTools_Method2_Patch
{
[HarmonyPostfix]
public static void AfterMethodCall(MethodInfo __result, Type type, string name)
{
if (!AccessToolsWarnings.isEnabled) return;
if (__result == null)
{
var method = (new StackTrace()).GetFrame(2).GetMethod();
Utility.Logging.LogWarning($"[{method.DeclaringType.FullName}.{method.Name}] AccessTools.Method(\"{type}\", \"{name}\") returned null result");
}
}
}
}
#endif

+ 4
- 1
CLre_server/API/Utility/Reflection.cs View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Game.DataLoader;
using GameNetworkLayer.Shared;
using HarmonyLib;
using NetworkFramework.Shared;
@@ -33,7 +35,8 @@ namespace CLre_server.API.Utility
public delegate void INetMsgServerListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBServer<T> proc) where T: struct, ISerializedNetData;


public delegate Dictionary<string, BaseData> IDataDB_GetValues();
// useful reflection functions
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
{


+ 35
- 8
CLre_server/Tweaks/TerrainModificationExclusionZone.cs View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using CLre_server.API.Synergy.Tweaks;
using CLre_server.API.Utility;
using Game.DataLoader;
using GameNetworkLayer.Shared;
using HarmonyLib;
@@ -12,6 +13,7 @@ using Svelto.DataStructures;
using Svelto.ECS;
using UnityEngine;
using User.Server;
using voxelfarm;

namespace CLre_server.Tweaks
{
@@ -104,8 +106,6 @@ namespace CLre_server.Tweaks
#endif
if (isPointInAABB)
{
result.Cell = item;
if (!isOwner)
{
result.Flags = RejectionFlag.Proximity
@@ -154,19 +154,24 @@ namespace CLre_server.Tweaks
[HarmonyPatch]
class TerrainModificationEngineServer_RemoveTerrainInput_Patch
{
private static API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
_netMessageSend = null;
private static object _netMsgServerSender;
// reflection caching
private static API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
_netMessageSend_CLre = null;

[HarmonyPrefix]
public static bool BeforeMethodCall(int senderPlayerId, ref ISerializedNetData data, object ____netMsgServerSender)
{
if (!CLre.Config.terrain_exclusion_zone) return true;
if (_netMessageSend == null)
_netMsgServerSender = ____netMsgServerSender;
if (_netMessageSend_CLre == null)
{
// cache reflection operations on first run
#if DEBUG
API.Utility.Logging.MetaLog("Building SendMessage delegate optimisation");
#endif
_netMessageSend = API.Utility.Reflection
_netMessageSend_CLre = API.Utility.Reflection
.MethodAsDelegate<
API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
>(
@@ -185,12 +190,34 @@ namespace CLre_server.Tweaks
#if DEBUG
API.Utility.Logging.MetaLog("Rejecting terrain modification");
#endif
// TODO optimize
Traverse tmid = Traverse.Create(data);
modifyPayload.resourceId = tmid.Property<uint>("resourceId").Value;
modifyPayload.hit = location;
//modifyPayload.materialIndex = tmid.Property<int>("materialIndex").Value;
modifyPayload.toolKey = tmid.Property<string>("toolKey").Value;
modifyPayload.toolMode = tmid.Property<Game.Handhelds.ToolModeType>("toolMode").Value;
switch (modifyPayload.toolMode)
{
case Game.Handhelds.ToolModeType.Block:
modifyPayload.hit.y -= 0.125f * 2; // each layer is 0.125 thick, block is 3 layers
break;
case Game.Handhelds.ToolModeType.Disc:
break;
case Game.Handhelds.ToolModeType.Voxel:
modifyPayload.toolMode = Game.Handhelds.ToolModeType.Disc; // voxels aren't replaced properly
break;
}
// signal client that stuff failed
_netMessageSend(NetworkDispatcherCode.TerrainModificationFailed, ref modifyPayload, senderPlayerId);
_netMessageSend_CLre(NetworkDispatcherCode.TerrainModificationFailed, ref modifyPayload, senderPlayerId);
// build terrain data for terrain replacement
#if DEBUG
API.Utility.Logging.MetaLog("Filling hole left by terrain modification");
#endif
}
return modifyPayload.Ok();
}
[HarmonyTargetMethod]
public static MethodBase Target()
{


Loading…
Cancel
Save