Skip to content

Commit

Permalink
Tweaks and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Patbox committed Feb 20, 2024
1 parent 8e3d4c0 commit 77d7611
Show file tree
Hide file tree
Showing 19 changed files with 168 additions and 48 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ your mod pack.

If you have a server and polymer based mods you are using include a resource pack, you might want to install
"bundled/packed/all" version of polymer contains AutoHost module, allowing you to set up automatic building and sending of packs
to clients.
to clients. See [this page](https://polymer.pb4.eu/latest/user/resource-pack-hosting) to learn about the setup.

If you use 1.18.x or older, use this instead: https://github.com/aws404/polypack-host

Expand Down
7 changes: 6 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ are represented on server the same as normal (vanilla/modded) ones allowing for

It is also should be fully compatible with close to all other mods and in case of found issues they are patched as soon as possible.

## Modules
## User guides

* [Resource Pack hosting](user/resource-pack-hosting)
* [Adding/Overriding assets in Resource Pack](user/resource-pack-custom-assets)

## Mod development / Library usage

### Polymer Core
`eu.pb4:polymer-core`
Expand Down
4 changes: 2 additions & 2 deletions docs/polymer-core/blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ For most basic uses, there are default implementation of `PolymerBlock`:
* `SimplePolymerBlock` - Same as vanilla `Block`.

### Selecting base polymer block type.
To change base block, you need to override `Block getPolymerBlock(BlockState)` method.
To change base block, you need to override `Block getPolymerBlock(BlockState state)` method.

You can also override `Block getPolymerBlock(ServerPlayerEntity, BlockState)` to replace blocks per player,
You can also override `Block getPolymerBlock(ServerPlayerEntity player, BlockState state)` to replace blocks per player,
however keep in mind they should ideally have same collisions.

Both of these methods can't return null. They can also point to other PolymerBlock instances, but keep
Expand Down
2 changes: 1 addition & 1 deletion docs/polymer-core/client-side.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ While Polymer by itself is mainly server side api, it includes some
client side functionality for mods to use. It allows you for example to display
vanilla friendly item for normal clients and custom models if it's present on server.

## Keeping modded item/block on compatible client.
## Keeping modded item/block/entity on compatible client.

To keep client side model for loading, you need to implement `PolymerKeepModel` interface
on your modded object. To enable it's decoding, just add `PolymerClientDecoded` interface for it.
Expand Down
2 changes: 1 addition & 1 deletion docs/polymer-core/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ All your code that interacts with Polymer should:

* Be thread safe - code can run on main server thread, player's connection thread
or client side rendering thread.
* Make sure to check every time you cast if it's really instance of it. Sometimes `World` won't be `ServerWorld`.
* Make sure to check every time you cast if it's really instance of it. Sometimes `World` won't be a `ServerWorld` instance.
* Never implement Polymer interfaces on Vanilla Items/Blocks with mixins, it will end up really, really badly.
* Never add new BlockStates to non-polymer blocks, as it will cause desyncs (see previous point)!
* Please don't even try using registry replacement, it will break many other mods (and polymer itself).
Expand Down
7 changes: 4 additions & 3 deletions docs/polymer-core/items.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ public int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayer
You can create server side Item Groups, which will be later synced with Polymer-compatible clients.
They also allow you to create server side Creative categories, that are accessible via `/polymer creative` command.

To create, it, you just need to call one of provided `PolymerItemGroupUtils.builder(Identifier)` static method.
Then you can create it just like regular ItemGroup.
To create, it, you just need to call one of provided `PolymerItemGroupUtils.builder()` static method.
Then you can create it just like regular ItemGroup, but instead of registering into vanilla registry, you use
`PolymerItemGroupUtils.registerPolymerItemGroup(Identifier id, ItemGroup group)

## Manipulation of non-polymer items
Sometimes, you might want to manipulate other vanilla/modded items without implementing
Expand Down Expand Up @@ -148,7 +149,7 @@ PolymerItemUtils.ITEM_MODIFICATION_EVENT.register(
You can also force item's mining speed to be calculated server side
(which happens by default to every PolymerItem).

Only thing you need to do is just listening to `BlockHelper.SERVER_SIDE_MINING_CHECK` event.
Only thing you need to do is just listening to `PolymerBlockUtils.SERVER_SIDE_MINING_CHECK` event.

Example use:
```
Expand Down
4 changes: 2 additions & 2 deletions docs/polymer-core/other.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ Then you can use it just like vanilla ones.
## StatusEffects

To create custom, server side status effects, you just need to implement PolymerStatusEffect on your
custom StatusEffect class. You can also override `StatusEffect getPolymerStatusEffect()` to display it
as vanilla one (otherwise they are hidden).
custom StatusEffect class. You can also override `StatusEffect getPolymerReplacement(ServerPlayerEntity player)` to display it
as vanilla one or null to make it invisible (default).

2 changes: 1 addition & 1 deletion docs/polymer-resource-pack/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ returns `true` if `modid` is valid.

This should be called ideally in your mod initializer.

Additionally, you can add assets manually by calling `PolymerRPBuilder.addData(String path, byte[] data)`.
Additionally, you can add assets manually by calling `ResourcePackBuilder.addData(String path, byte[] data)`.
You can get instance of it by listening to `PolymerResourcePackUtils.RESOURCE_PACK_CREATION_EVENT`.
Just keep in minds that new one will be created every time resource pack is generated.

Expand Down
20 changes: 20 additions & 0 deletions docs/user/resource-pack-custom-assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Adding custom assets to Resource Pack

Polymer has builtin support for adding and overriding assets to generated resource pack. You can do it in multiple ways.

## Base folders
You can add your assets to `polymer/source_assets` and/or `polymer/override_assets` folders.
These folders might not exist by default so you will need to create them by hand.
The `source_assets` folder is applied first, before any mod. The `override_assets` folder is applied last, after generation/copying of most other files.
For most cases, you likely want to use `source_assets`. These folders both use vanilla resource pack structure, with `pack.mcmeta` and `pack.png` being optional
and replacing default Polymer-generated one.

## Adding resource packs zips or mods
To add custom resource packs, open `config/polymer/resource-pack.json` file.
Then look at list in `"include_zips"` and add paths to zips with your custom resource packs.
These paths are relative to server's root folder.
To copy assets from mods, you can either use the zip method or add their modid to `"include_mod_assets"`.
Unlike with method above, the only copied folder is included `assets` folder, ignoring anything else, making
it more suitable for merging resource packs without adding invalid metadata.

This setting will only update on server restart.
36 changes: 36 additions & 0 deletions docs/user/resource-pack-hosting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Hosting Resource Packs

Some Polymer mods (or if you use PolyMc) might require or allow for optional resource packs.
Polymer has builtin module (AutoHost) to allow for automatic generation and hosting of resource packs
on server start.

## Installation / Checking if it's present
To check if it's present, start the server and check if `config/polymer/auto-host.json` exists.
If it doesn't install correct version of [Polymer from Modrinth](https://modrinth.com/mod/polymer).

## Enabling AutoHost

### For basic server setup (direct server without proxies, reusing port, 0.7.1+1.20.4 or newer)
Start the server at least once. Then open the config file in `config/polymer/auto-host.json`
and change the value in field `"enabled"` from `false` to `true`. Then save the file and restart the server!
It should automatically apply the resource pack after it finishes generation.

### For proxy setups (reuses port, 0.7.1+1.20.4 or newer)
Do everything as above.
If your server is behind proxy, you need to change the string for `"forced_address"` from `""` to
`"http://serveraddress.net:port"` (for example `"http://server.net:25565"`). The port and address isn't required
to match server internal one, if you use http proxies.

### Custom port setup (0.4.8+1.19.4 or newer)
Start the server at least once. Then open the config file in `config/polymer/auto-host.json`
and change the value in field `"enabled"` from `false` to `true`.
Next set `"type"` to `"polymer:http_server"`. Then replace `"settings"` with
```json
{
"port": 25567,
"external_address": "http://localhost:25567/"
}
```
You can change port to any other you need, just make sure the external address is accessible from the outside.
Then save the file and restart the server!
It should automatically apply the resource pack after it finishes generation.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fabric_version=0.91.1+1.20.4

maven_group = eu.pb4

mod_version = 0.7.6-dev
mod_version = 0.7.6

minecraft_version_supported = ">=1.20.3-"

Expand Down
3 changes: 3 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ repo_name: Patbox/polymer

nav:
- index.md
- User Guides:
- user/resource-pack-hosting.md
- user/resource-pack-custom-assets.md
- Polymer Core:
- polymer-core/getting-started.md
- polymer-core/items.md
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package eu.pb4.polymer.autohost.impl;

import com.mojang.brigadier.arguments.BoolArgumentType;
import eu.pb4.polymer.autohost.api.ResourcePackDataProvider;
import eu.pb4.polymer.autohost.impl.providers.AbstractProvider;
import eu.pb4.polymer.autohost.impl.providers.NettyProvider;
import eu.pb4.polymer.autohost.impl.providers.EmptyProvider;
import eu.pb4.polymer.autohost.impl.providers.StandaloneWebServerProvider;
Expand All @@ -26,6 +28,7 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;

public class AutoHost implements ModInitializer {
Expand Down Expand Up @@ -151,6 +154,13 @@ public void onInitialize() {
});
return 0;
}));

c.then(literal("force_ready").then(argument("value", BoolArgumentType.bool()).executes((ctx) -> {
if (provider instanceof AbstractProvider abs) {
abs.isPackReady = BoolArgumentType.getBool(ctx, "value");
}
return 0;
})));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,48 @@
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class AutoHostTask implements ServerPlayerConfigurationTask {
public static final Key KEY = new Key("polymer:autohost/send_packs");
private final Collection<MinecraftServer.ServerResourcePackProperties> packs;

private final Set<UUID> requiredPacks = new HashSet<>();
private final Set<UUID> waitingFor = new HashSet<>();
private final Supplier<Collection<MinecraftServer.ServerResourcePackProperties>> delayed;
private final BooleanSupplier isReady;
private boolean hasDelayed;

public AutoHostTask(Collection<MinecraftServer.ServerResourcePackProperties> properties) {
public AutoHostTask(Collection<MinecraftServer.ServerResourcePackProperties> properties, boolean hasDelayed,
Supplier<Collection<MinecraftServer.ServerResourcePackProperties>> delayed, BooleanSupplier isReady) {
this.packs = properties;
for (var pack : packs) {
if (pack.isRequired()) {
requiredPacks.add(pack.id());
}
waitingFor.add(pack.id());
}
this.hasDelayed = hasDelayed;
this.delayed = delayed;
this.isReady = isReady;
}

public void tick(Consumer<Packet<?>> sender) {
if (this.hasDelayed && this.isReady.getAsBoolean()) {
var delayed = this.delayed.get();
for (var pack : delayed) {
if (pack.isRequired()) {
requiredPacks.add(pack.id());
}
waitingFor.add(pack.id());
}
for (var pack : delayed) {
sender.accept(new ResourcePackSendS2CPacket(pack.id(), pack.url(), pack.hash(), pack.isRequired(), pack.prompt()));
}
this.hasDelayed = false;
}
}

@Override
Expand Down Expand Up @@ -56,6 +81,6 @@ public boolean onStatus(ServerConfigurationNetworkHandler handler, UUID id, Reso
this.waitingFor.remove(id);
}

return this.waitingFor.isEmpty();
return this.waitingFor.isEmpty() && !this.hasDelayed;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import eu.pb4.polymer.autohost.impl.AutoHost;
import eu.pb4.polymer.common.impl.CommonImpl;
import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils;
import eu.pb4.polymer.resourcepack.api.ResourcePackBuilder;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.MinecraftServer;
import org.apache.http.HttpStatus;
Expand All @@ -19,45 +20,54 @@
import java.nio.file.Files;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;

public abstract class AbstractProvider implements ResourcePackDataProvider {
public long size = 0;
public String hash = "";
public long lastUpdate = 0;
public boolean enabled;
public boolean isPackReady = false;
private Consumer<ResourcePackBuilder> eventA;
private Runnable eventB;

public void serverStarted(MinecraftServer minecraftServer) {
this.enabled = true;

this.isPackReady = true;
updateHash();
this.isPackReady = false;

PolymerResourcePackUtils.RESOURCE_PACK_CREATION_EVENT.register((x) -> {
this.eventA = PolymerResourcePackUtils.RESOURCE_PACK_CREATION_EVENT.registerRet((x) -> {
isPackReady = false;
});

PolymerResourcePackUtils.RESOURCE_PACK_FINISHED_EVENT.register(() -> {
isPackReady = true;
this.eventB = PolymerResourcePackUtils.RESOURCE_PACK_FINISHED_EVENT.registerRet(() -> {
updateHash();
isPackReady = true;
});

AutoHost.generateAndCall(minecraftServer, minecraftServer::sendMessage, () -> {
});
AutoHost.generateAndCall(minecraftServer, minecraftServer::sendMessage, () -> {});
}

@Override
public void serverStopped(MinecraftServer server) {
PolymerResourcePackUtils.RESOURCE_PACK_CREATION_EVENT.unregister(this.eventA);
PolymerResourcePackUtils.RESOURCE_PACK_FINISHED_EVENT.unregister(this.eventB);
}

protected boolean updateHash() {
try {
hash = com.google.common.io.Files.asByteSource(PolymerResourcePackUtils.getMainPath().toFile()).hash(Hashing.sha1()).toString();
size = Files.size(PolymerResourcePackUtils.getMainPath());
lastUpdate = Files.getLastModifiedTime(PolymerResourcePackUtils.getMainPath()).toMillis();
return true;
if (Files.exists(PolymerResourcePackUtils.getMainPath())) {
hash = com.google.common.io.Files.asByteSource(PolymerResourcePackUtils.getMainPath().toFile()).hash(Hashing.sha1()).toString();
size = Files.size(PolymerResourcePackUtils.getMainPath());
lastUpdate = Files.getLastModifiedTime(PolymerResourcePackUtils.getMainPath()).toMillis();
return true;
}
} catch (Exception e) {
hash = "";
size = 0;
return false;
}

}
hash = "";
size = 0;
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public record EmptyProvider() implements ResourcePackDataProvider {

@Override
public boolean isReady() {
return false;
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.ArrayList;
import java.util.Queue;
import java.util.*;

@Mixin(ServerConfigurationNetworkHandler.class)
public abstract class ServerConfigurationNetworkHandlerMixin extends ServerCommonNetworkHandler {
Expand All @@ -39,10 +38,13 @@ public ServerConfigurationNetworkHandlerMixin(MinecraftServer server, ClientConn
private void polymerAutoHost$addTask(CallbackInfo ci) {
if (AutoHost.config.enabled) {
var x = new ArrayList<MinecraftServer.ServerResourcePackProperties>();
x.addAll(AutoHost.provider.getProperties(this.connection));
var ready = AutoHost.provider.isReady();
if (ready) {
x.addAll(AutoHost.provider.getProperties(this.connection));
}
x.addAll(AutoHost.GLOBAL_RESOURCE_PACKS);

this.tasks.add(new AutoHostTask(x));
this.tasks.add(new AutoHostTask(x, !ready, () -> AutoHost.provider.getProperties(this.connection), AutoHost.provider::isReady));
}
}

Expand All @@ -53,6 +55,13 @@ private void onStatus(ResourcePackStatusC2SPacket packet, CallbackInfo ci) {
}
}

@Inject(method = "tick", at = @At("TAIL"))
private void tickTask(CallbackInfo ci) {
if (this.currentTask instanceof AutoHostTask task) {
task.tick(this::sendPacket);
}
}

@WrapWithCondition(method = "onResourcePackStatus", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerConfigurationNetworkHandler;onTaskFinished(Lnet/minecraft/server/network/ServerPlayerConfigurationTask$Key;)V"))
private boolean checkType(ServerConfigurationNetworkHandler instance, ServerPlayerConfigurationTask.Key key, @Local ResourcePackStatusC2SPacket packet) {
return key != SendResourcePackTask.KEY
Expand Down
Loading

0 comments on commit 77d7611

Please sign in to comment.