Add client-side terrain replacement when terrain add is rejected
This commit is contained in:
parent
7c76c27126
commit
476d6382da
14 changed files with 427 additions and 45 deletions
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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;
|
||||
|
@ -73,11 +71,14 @@ namespace CLre.API.Synergy
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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(); };
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
CLre/Fixes/TerrainModifyReset.cs
Normal file
244
CLre/Fixes/TerrainModifyReset.cs
Normal 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");
|
||||
}
|
||||
}*/
|
||||
}
|
|
@ -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,7 +11,13 @@ 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()
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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,6 +35,7 @@ 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
|
||||
|
|
|
@ -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 object _netMsgServerSender;
|
||||
|
||||
// reflection caching
|
||||
private static API.Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreTerrainModifyRejection>
|
||||
_netMessageSend = null;
|
||||
_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,8 +190,30 @@ 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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue